From 514ea892650d96effa6abfef41b12bdb0e83a93d Mon Sep 17 00:00:00 2001 From: Kuba Sekowski Date: Wed, 28 Jan 2026 14:16:28 +0100 Subject: [PATCH] Remove tests and test-related configuration from the public repository --- .config/karma/base.js | 80 - .config/karma/debug.js | 13 - .eslintignore | 5 - .eslintrc.js | 22 +- .github/codecov.yml | 14 - .github/workflows/performance.yml | 69 - .github/workflows/test.yml | 67 - .gitignore | 3 - .typedoc.ts | 1 - Makefile | 18 +- docs/guide/building.md | 16 - jasmine.json | 13 - jest.config.js | 60 - karma.conf.js | 8 - karma.starter.ts | 17 - package-lock.json | 29437 ++++++---------- package.json | 38 +- test/compatibility/README.md | 34 - .../compare-evaluation-results.ts | 275 - test/compatibility/test-compatibility.sh | 13 - .../test_data/basic-arithmetic.xlsx | Bin 10253 -> 0 bytes .../test_data/logical-conditions.xlsx | Bin 11669 -> 0 bytes .../compatibility/test_data/lookup-basic.xlsx | Bin 15713 -> 0 bytes test/compatibility/test_data/sample_file.xlsx | Bin 8912 -> 0 bytes .../test_data/text-functions.xlsx | Bin 11008 -> 0 bytes test/performance/basic-benchmark.ts | 25 - test/performance/benchmark.ts | 169 - test/performance/compare-benchmarks.ts | 93 - test/performance/cruds-benchmark.ts | 67 - test/performance/run-basic-benchmark.ts | 9 - test/performance/run-cruds-benchmark.ts | 9 - test/performance/sheets/05-sheet-t.ts | 30 - test/performance/sheets/09-sheet-a.ts | 31 - test/performance/sheets/10-sheet-b.ts | 33 - test/performance/sheets/column-ranges.ts | 32 - test/performance/utils/stats.ts | 87 - test/performance/utils/utils.ts | 17 - test/performance/write-to-file.ts | 25 - test/unit/AbsoluteCellRange.spec.ts | 103 - test/unit/CellContentParser.spec.ts | 161 - test/unit/CellValueExporter.spec.ts | 73 - test/unit/ColumnsSpan.spec.ts | 102 - test/unit/RowsSpan.spec.ts | 102 - test/unit/_setupFiles/babel.js | 3 - test/unit/_setupFiles/bootstrap.ts | 59 - test/unit/_setupFiles/globalSetup.ts | 15 - test/unit/_setupFiles/jest/bootstrap.ts | 9 - test/unit/_setupFiles/jest/toEqualError.ts | 29 - test/unit/_setupFiles/jsdom.js | 7 - test/unit/_setupFiles/matchers/index.ts | 3 - .../_setupFiles/matchers/toContainEqual.ts | 25 - .../unit/_setupFiles/matchers/toEqualError.ts | 34 - .../_setupFiles/matchers/toMatchObject.ts | 25 - test/unit/address-mapping.spec.ts | 714 - .../address-representation-converters.spec.ts | 122 - test/unit/arrays-integration.spec.ts | 29 - test/unit/arrays.spec.ts | 537 - test/unit/build-engine.spec.ts | 114 - test/unit/cache-order.spec.ts | 28 - test/unit/column-index.spec.ts | 844 - test/unit/column-range.spec.ts | 97 - test/unit/computation-suspension.spec.ts | 227 - test/unit/config.spec.ts | 423 - test/unit/content-changes.spec.ts | 113 - test/unit/criterion.spec.ts | 82 - test/unit/crud-random.spec.ts | 277 - .../cruds/adding-columns-dependencies.spec.ts | 533 - test/unit/cruds/adding-columns.spec.ts | 473 - .../cruds/adding-row-dependencies.spec.ts | 646 - test/unit/cruds/adding-row.spec.ts | 481 - test/unit/cruds/adding-sheet.spec.ts | 495 - test/unit/cruds/batch-operations.spec.ts | 139 - test/unit/cruds/change-cell-content.spec.ts | 1253 - test/unit/cruds/clear-sheet.spec.ts | 105 - test/unit/cruds/copy-paste.spec.ts | 525 - test/unit/cruds/cut-paste.spec.ts | 1024 - test/unit/cruds/move-cells.spec.ts | 1118 - test/unit/cruds/move-columns.spec.ts | 331 - test/unit/cruds/move-rows.spec.ts | 326 - test/unit/cruds/removing-columns.spec.ts | 1020 - test/unit/cruds/removing-rows.spec.ts | 1131 - test/unit/cruds/removing-sheet.spec.ts | 860 - test/unit/cruds/rename-sheet.spec.ts | 583 - test/unit/cruds/replace-sheet-content.spec.ts | 118 - test/unit/cruds/set-column-order.spec.ts | 363 - test/unit/cruds/set-matrix-empty.spec.ts | 121 - test/unit/cruds/set-row-order.spec.ts | 390 - test/unit/custom-functions.spec.ts | 682 - test/unit/date.spec.ts | 303 - ...cy-graph-sheet-reference-registrar.spec.ts | 72 - ...-of-scope-dependencies-transformer.spec.ts | 10 - .../combined-transformer.spec.ts | 29 - .../remove-columns-transformer.spec.ts | 36 - .../remove-rows-transformer.spec.ts | 45 - .../transformer.spec.ts | 119 - .../dependent-formula-transformer.spec.ts | 14 - test/unit/destruct.spec.ts | 30 - test/unit/emitting-events.spec.ts | 237 - test/unit/engine.spec.ts | 1252 - test/unit/error-address-preservation.spec.ts | 86 - test/unit/escaping-support.spec.ts | 10 - test/unit/extending-plugins.spec.ts | 37 - test/unit/find-boundaries.spec.ts | 83 - test/unit/format/format-interpreter.spec.ts | 50 - test/unit/format/format-parser.spec.ts | 84 - test/unit/functions-metadata.spec.ts | 23 - test/unit/generate-cells-range.spec.ts | 173 - test/unit/generatorUtils.spec.ts | 52 - test/unit/graph-builder.spec.ts | 165 - test/unit/graph-dependencies-queries.spec.ts | 169 - test/unit/graph-garbage-collection.spec.ts | 350 - test/unit/graph-vertex.spec.ts | 17 - test/unit/graph.spec.ts | 554 - test/unit/graphComparator.ts | 133 - test/unit/helpers/licenseKeyValidator.spec.ts | 60 - test/unit/i18n.spec.ts | 194 - test/unit/interpreter.spec.ts | 348 - .../interpreter/aggregation-arguments.spec.ts | 74 - test/unit/interpreter/aliases.spec.ts | 208 - test/unit/interpreter/binary-search.spec.ts | 122 - .../interpreter/boolean-operators.spec.ts | 340 - test/unit/interpreter/coercions.spec.ts | 378 - .../criterion-computations.spec.ts | 318 - test/unit/interpreter/cyclical-deps.spec.ts | 28 - .../date-and-time-arithmetic.spec.ts | 311 - test/unit/interpreter/error-literals.spec.ts | 92 - test/unit/interpreter/function-abs.spec.ts | 51 - test/unit/interpreter/function-acos.spec.ts | 68 - test/unit/interpreter/function-acosh.spec.ts | 49 - test/unit/interpreter/function-acot.spec.ts | 44 - test/unit/interpreter/function-acoth.spec.ts | 52 - .../unit/interpreter/function-address.spec.ts | 299 - test/unit/interpreter/function-and.spec.ts | 95 - test/unit/interpreter/function-arabic.spec.ts | 102 - .../function-array_constrain.spec.ts | 64 - .../interpreter/function-arrayformula.spec.ts | 37 - test/unit/interpreter/function-asin.spec.ts | 66 - test/unit/interpreter/function-asinh.spec.ts | 42 - test/unit/interpreter/function-atan.spec.ts | 41 - test/unit/interpreter/function-atan2.spec.ts | 47 - test/unit/interpreter/function-atanh.spec.ts | 53 - test/unit/interpreter/function-avedev.spec.ts | 88 - .../unit/interpreter/function-average.spec.ts | 73 - .../interpreter/function-averagea.spec.ts | 74 - .../interpreter/function-averageif.spec.ts | 147 - test/unit/interpreter/function-base.spec.ts | 102 - .../unit/interpreter/function-besseli.spec.ts | 70 - .../unit/interpreter/function-besselj.spec.ts | 70 - .../unit/interpreter/function-besselk.spec.ts | 70 - .../unit/interpreter/function-bessely.spec.ts | 70 - .../interpreter/function-beta.dist.spec.ts | 82 - .../interpreter/function-beta.inv.spec.ts | 70 - .../unit/interpreter/function-bin2dec.spec.ts | 69 - .../unit/interpreter/function-bin2hex.spec.ts | 111 - .../unit/interpreter/function-bin2oct.spec.ts | 111 - .../interpreter/function-binom.dist.spec.ts | 78 - .../interpreter/function-binom.inv.spec.ts | 168 - test/unit/interpreter/function-bitand.spec.ts | 70 - .../interpreter/function-bitlshift.spec.ts | 95 - test/unit/interpreter/function-bitor.spec.ts | 72 - .../interpreter/function-bitrshift.spec.ts | 95 - test/unit/interpreter/function-bitxor.spec.ts | 72 - .../interpreter/function-ceiling.math.spec.ts | 88 - .../function-ceiling.precise.spec.ts | 61 - .../unit/interpreter/function-ceiling.spec.ts | 61 - test/unit/interpreter/function-char.spec.ts | 72 - .../function-chisq.dist.rt.spec.ts | 54 - .../interpreter/function-chisq.dist.spec.ts | 66 - .../interpreter/function-chisq.inv.rt.spec.ts | 58 - .../interpreter/function-chisq.inv.spec.ts | 58 - .../interpreter/function-chisq.test.spec.ts | 107 - test/unit/interpreter/function-choose.spec.ts | 77 - test/unit/interpreter/function-clean.spec.ts | 48 - test/unit/interpreter/function-code.spec.ts | 75 - test/unit/interpreter/function-column.spec.ts | 117 - .../unit/interpreter/function-columns.spec.ts | 80 - test/unit/interpreter/function-combin.spec.ts | 81 - .../unit/interpreter/function-combina.spec.ts | 80 - .../unit/interpreter/function-complex.spec.ts | 73 - .../interpreter/function-concatenate.spec.ts | 63 - .../function-confidence.norm.spec.ts | 66 - .../interpreter/function-confidence.t.spec.ts | 70 - test/unit/interpreter/function-correl.spec.ts | 92 - test/unit/interpreter/function-cos.spec.ts | 42 - test/unit/interpreter/function-cosh.spec.ts | 42 - test/unit/interpreter/function-cot.spec.ts | 51 - test/unit/interpreter/function-coth.spec.ts | 51 - test/unit/interpreter/function-count.spec.ts | 75 - test/unit/interpreter/function-counta.spec.ts | 76 - .../interpreter/function-countblank.spec.ts | 60 - .../unit/interpreter/function-countif.spec.ts | 147 - .../interpreter/function-countifs.spec.ts | 140 - .../interpreter/function-countunique.spec.ts | 94 - .../interpreter/function-covariance.p.spec.ts | 90 - .../interpreter/function-covariance.s.spec.ts | 92 - test/unit/interpreter/function-csc.spec.ts | 49 - test/unit/interpreter/function-csch.spec.ts | 48 - .../unit/interpreter/function-cumimpt.spec.ts | 33 - .../interpreter/function-cumprinc.spec.ts | 33 - test/unit/interpreter/function-date.spec.ts | 222 - .../unit/interpreter/function-datedif.spec.ts | 349 - .../interpreter/function-datevalue.spec.ts | 54 - test/unit/interpreter/function-day.spec.ts | 247 - test/unit/interpreter/function-days.spec.ts | 75 - .../unit/interpreter/function-days360.spec.ts | 70 - test/unit/interpreter/function-db.spec.ts | 56 - test/unit/interpreter/function-ddb.spec.ts | 64 - .../unit/interpreter/function-dec2bin.spec.ts | 117 - .../unit/interpreter/function-dec2hex.spec.ts | 107 - .../unit/interpreter/function-dec2oct.spec.ts | 107 - .../unit/interpreter/function-decimal.spec.ts | 80 - .../unit/interpreter/function-degrees.spec.ts | 51 - test/unit/interpreter/function-delta.spec.ts | 60 - test/unit/interpreter/function-devsq.spec.ts | 85 - .../interpreter/function-dollarde.spec.ts | 61 - .../interpreter/function-dollarfr.spec.ts | 61 - test/unit/interpreter/function-edate.spec.ts | 136 - test/unit/interpreter/function-effect.spec.ts | 27 - .../unit/interpreter/function-eomonth.spec.ts | 154 - test/unit/interpreter/function-erf.spec.ts | 52 - test/unit/interpreter/function-erfc.spec.ts | 46 - test/unit/interpreter/function-even.spec.ts | 50 - test/unit/interpreter/function-exact.spec.ts | 71 - test/unit/interpreter/function-exp.spec.ts | 51 - .../interpreter/function-expon.dist.spec.ts | 60 - .../interpreter/function-f.dist.rt.spec.ts | 62 - test/unit/interpreter/function-f.dist.spec.ts | 74 - .../interpreter/function-f.inv.rt.spec.ts | 62 - test/unit/interpreter/function-f.inv.spec.ts | 62 - test/unit/interpreter/function-f.test.spec.ts | 78 - test/unit/interpreter/function-fact.spec.ts | 68 - .../interpreter/function-factdouble.spec.ts | 68 - test/unit/interpreter/function-false.spec.ts | 18 - test/unit/interpreter/function-filter.spec.ts | 71 - test/unit/interpreter/function-find.spec.ts | 81 - test/unit/interpreter/function-fisher.spec.ts | 44 - .../interpreter/function-fisherinv.spec.ts | 36 - .../interpreter/function-floor.math.spec.ts | 88 - .../function-floor.precise.spec.ts | 61 - test/unit/interpreter/function-floor.spec.ts | 61 - .../interpreter/function-formulatext.spec.ts | 97 - test/unit/interpreter/function-fv.spec.ts | 28 - .../interpreter/function-fvschedule.spec.ts | 38 - .../interpreter/function-gamma.dist.spec.ts | 65 - .../interpreter/function-gamma.inv.spec.ts | 55 - test/unit/interpreter/function-gamma.spec.ts | 50 - .../unit/interpreter/function-gammaln.spec.ts | 44 - test/unit/interpreter/function-gauss.spec.ts | 36 - test/unit/interpreter/function-gcd.spec.ts | 117 - .../unit/interpreter/function-geomean.spec.ts | 94 - .../unit/interpreter/function-harmean.spec.ts | 94 - .../unit/interpreter/function-hex2bin.spec.ts | 121 - .../unit/interpreter/function-hex2dec.spec.ts | 89 - .../unit/interpreter/function-hex2oct.spec.ts | 137 - test/unit/interpreter/function-hfadd.spec.ts | 56 - .../interpreter/function-hfconcat.spec.ts | 46 - .../interpreter/function-hfdivide.spec.ts | 58 - test/unit/interpreter/function-hfeq.spec.ts | 56 - test/unit/interpreter/function-hfgt.spec.ts | 56 - test/unit/interpreter/function-hfgte.spec.ts | 56 - test/unit/interpreter/function-hflt.spec.ts | 56 - test/unit/interpreter/function-hflte.spec.ts | 56 - .../unit/interpreter/function-hfminus.spec.ts | 56 - .../interpreter/function-hfmultiply.spec.ts | 56 - test/unit/interpreter/function-hfne.spec.ts | 56 - test/unit/interpreter/function-hfpow.spec.ts | 48 - .../interpreter/function-hfuminus.spec.ts | 50 - .../function-hfunary_percent.spec.ts | 46 - .../unit/interpreter/function-hfuplus.spec.ts | 48 - .../unit/interpreter/function-hlookup.spec.ts | 358 - test/unit/interpreter/function-hour.spec.ts | 47 - .../interpreter/function-hyperlink.spec.ts | 49 - .../interpreter/function-hypgeom.dist.spec.ts | 106 - test/unit/interpreter/function-if.spec.ts | 139 - .../unit/interpreter/function-iferror.spec.ts | 67 - test/unit/interpreter/function-ifna.spec.ts | 79 - test/unit/interpreter/function-ifs.spec.ts | 58 - test/unit/interpreter/function-imabs.spec.ts | 35 - .../interpreter/function-imaginary.spec.ts | 35 - .../interpreter/function-imargument.spec.ts | 35 - .../interpreter/function-imconjugate.spec.ts | 35 - test/unit/interpreter/function-imcos.spec.ts | 35 - test/unit/interpreter/function-imcosh.spec.ts | 35 - test/unit/interpreter/function-imcot.spec.ts | 35 - test/unit/interpreter/function-imcsc.spec.ts | 35 - test/unit/interpreter/function-imcsch.spec.ts | 35 - test/unit/interpreter/function-imdiv.spec.ts | 37 - test/unit/interpreter/function-imexp.spec.ts | 35 - test/unit/interpreter/function-imln.spec.ts | 35 - .../unit/interpreter/function-imlog10.spec.ts | 35 - test/unit/interpreter/function-imlog2.spec.ts | 35 - .../unit/interpreter/function-impower.spec.ts | 43 - .../interpreter/function-improduct.spec.ts | 51 - test/unit/interpreter/function-imreal.spec.ts | 35 - test/unit/interpreter/function-imsec.spec.ts | 35 - test/unit/interpreter/function-imsech.spec.ts | 35 - test/unit/interpreter/function-imsin.spec.ts | 35 - test/unit/interpreter/function-imsinh.spec.ts | 35 - test/unit/interpreter/function-imsqrt.spec.ts | 35 - test/unit/interpreter/function-imsub.spec.ts | 37 - test/unit/interpreter/function-imsum.spec.ts | 51 - test/unit/interpreter/function-imtan.spec.ts | 35 - test/unit/interpreter/function-index.spec.ts | 118 - test/unit/interpreter/function-int.spec.ts | 50 - .../interpreter/function-interval.spec.ts | 49 - test/unit/interpreter/function-ipmt.spec.ts | 26 - .../interpreter/function-isbinary.spec.ts | 24 - .../unit/interpreter/function-isblank.spec.ts | 56 - test/unit/interpreter/function-iserr.spec.ts | 53 - .../unit/interpreter/function-iserror.spec.ts | 46 - test/unit/interpreter/function-iseven.spec.ts | 41 - .../interpreter/function-isformula.spec.ts | 88 - .../interpreter/function-islogical.spec.ts | 46 - test/unit/interpreter/function-isna.spec.ts | 42 - .../interpreter/function-isnontext.spec.ts | 45 - .../interpreter/function-isnumber.spec.ts | 34 - test/unit/interpreter/function-isodd.spec.ts | 41 - .../interpreter/function-isoweeknum.spec.ts | 98 - test/unit/interpreter/function-ispmt.spec.ts | 25 - test/unit/interpreter/function-isref.spec.ts | 62 - test/unit/interpreter/function-istext.spec.ts | 45 - test/unit/interpreter/function-large.spec.ts | 87 - test/unit/interpreter/function-lcm.spec.ts | 117 - test/unit/interpreter/function-left.spec.ts | 81 - test/unit/interpreter/function-len.spec.ts | 35 - test/unit/interpreter/function-ln.spec.ts | 55 - test/unit/interpreter/function-log.spec.ts | 89 - test/unit/interpreter/function-log10.spec.ts | 55 - .../interpreter/function-lognorm.dist.spec.ts | 67 - .../interpreter/function-lognorm.inv.spec.ts | 54 - test/unit/interpreter/function-lower.spec.ts | 41 - test/unit/interpreter/function-match.spec.ts | 758 - test/unit/interpreter/function-max.spec.ts | 74 - test/unit/interpreter/function-maxa.spec.ts | 77 - test/unit/interpreter/function-maxifs.spec.ts | 259 - test/unit/interpreter/function-median.spec.ts | 108 - test/unit/interpreter/function-mid.spec.ts | 81 - test/unit/interpreter/function-min.spec.ts | 74 - test/unit/interpreter/function-mina.spec.ts | 74 - test/unit/interpreter/function-minifs.spec.ts | 259 - test/unit/interpreter/function-minute.spec.ts | 47 - test/unit/interpreter/function-mirr.spec.ts | 67 - test/unit/interpreter/function-modulo.spec.ts | 48 - test/unit/interpreter/function-month.spec.ts | 229 - test/unit/interpreter/function-mround.spec.ts | 78 - .../interpreter/function-multinomial.spec.ts | 93 - test/unit/interpreter/function-na.spec.ts | 13 - .../function-negbinom.dist.spec.ts | 82 - .../function-networkdays.intl.spec.ts | 103 - .../interpreter/function-networkdays.spec.ts | 73 - .../unit/interpreter/function-nominal.spec.ts | 27 - .../interpreter/function-norm.dist.spec.ts | 60 - .../interpreter/function-norm.inv.spec.ts | 56 - .../interpreter/function-norm.s.dist.spec.ts | 50 - .../interpreter/function-norm.s.inv.spec.ts | 48 - test/unit/interpreter/function-not.spec.ts | 41 - test/unit/interpreter/function-now.spec.ts | 76 - test/unit/interpreter/function-nper.spec.ts | 39 - test/unit/interpreter/function-npv.spec.ts | 63 - .../unit/interpreter/function-oct2bin.spec.ts | 131 - .../unit/interpreter/function-oct2dec.spec.ts | 85 - .../unit/interpreter/function-oct2hex.spec.ts | 125 - test/unit/interpreter/function-odd.spec.ts | 50 - test/unit/interpreter/function-or.spec.ts | 98 - .../interpreter/function-pduration.spec.ts | 34 - test/unit/interpreter/function-phi.spec.ts | 36 - test/unit/interpreter/function-pi.spec.ts | 19 - test/unit/interpreter/function-pmt.spec.ts | 48 - .../interpreter/function-poisson.dist.spec.ts | 72 - test/unit/interpreter/function-power.spec.ts | 72 - test/unit/interpreter/function-ppmt.spec.ts | 26 - .../unit/interpreter/function-product.spec.ts | 24 - test/unit/interpreter/function-proper.spec.ts | 59 - test/unit/interpreter/function-pv.spec.ts | 40 - .../interpreter/function-quotient.spec.ts | 60 - .../unit/interpreter/function-radians.spec.ts | 51 - test/unit/interpreter/function-rand.spec.ts | 23 - .../interpreter/function-randbetween.spec.ts | 88 - test/unit/interpreter/function-rate.spec.ts | 233 - .../unit/interpreter/function-replace.spec.ts | 79 - test/unit/interpreter/function-rept.spec.ts | 61 - test/unit/interpreter/function-right.spec.ts | 77 - test/unit/interpreter/function-roman.spec.ts | 85 - test/unit/interpreter/function-round.spec.ts | 79 - .../interpreter/function-rounddown.spec.ts | 70 - .../unit/interpreter/function-roundup.spec.ts | 70 - test/unit/interpreter/function-row.spec.ts | 87 - test/unit/interpreter/function-rows.spec.ts | 76 - test/unit/interpreter/function-rri.spec.ts | 31 - test/unit/interpreter/function-rsq.spec.ts | 92 - test/unit/interpreter/function-search.spec.ts | 157 - test/unit/interpreter/function-sec.spec.ts | 50 - test/unit/interpreter/function-sech.spec.ts | 42 - test/unit/interpreter/function-second.spec.ts | 47 - .../interpreter/function-seriessum.spec.ts | 61 - test/unit/interpreter/function-sheet.spec.ts | 88 - test/unit/interpreter/function-sheets.spec.ts | 43 - test/unit/interpreter/function-sign.spec.ts | 36 - test/unit/interpreter/function-sin.spec.ts | 42 - test/unit/interpreter/function-sinh.spec.ts | 42 - test/unit/interpreter/function-skew.p.spec.ts | 67 - test/unit/interpreter/function-skew.spec.ts | 67 - test/unit/interpreter/function-sln.spec.ts | 26 - test/unit/interpreter/function-slope.spec.ts | 93 - test/unit/interpreter/function-small.spec.ts | 86 - test/unit/interpreter/function-split.spec.ts | 50 - test/unit/interpreter/function-sqrt.spec.ts | 46 - test/unit/interpreter/function-sqrtpi.spec.ts | 35 - .../interpreter/function-standardize.spec.ts | 48 - .../unit/interpreter/function-stdev.p.spec.ts | 43 - .../unit/interpreter/function-stdev.s.spec.ts | 43 - test/unit/interpreter/function-stdeva.spec.ts | 43 - .../unit/interpreter/function-stdevpa.spec.ts | 43 - test/unit/interpreter/function-steyx.spec.ts | 93 - .../interpreter/function-substitute.spec.ts | 145 - .../interpreter/function-subtotal.spec.ts | 173 - test/unit/interpreter/function-sum.spec.ts | 254 - test/unit/interpreter/function-sumif.spec.ts | 773 - .../interpreter/function-sumproduct.spec.ts | 206 - test/unit/interpreter/function-sumsq.spec.ts | 85 - .../interpreter/function-sumx2my2.spec.ts | 58 - .../interpreter/function-sumx2py2.spec.ts | 58 - .../unit/interpreter/function-sumxmy2.spec.ts | 58 - test/unit/interpreter/function-switch.spec.ts | 68 - test/unit/interpreter/function-syd.spec.ts | 27 - .../interpreter/function-t.dist.2t.spec.ts | 58 - .../interpreter/function-t.dist.rt.spec.ts | 58 - test/unit/interpreter/function-t.dist.spec.ts | 69 - .../interpreter/function-t.inv.2t.spec.ts | 64 - test/unit/interpreter/function-t.inv.spec.ts | 63 - test/unit/interpreter/function-t.spec.ts | 47 - test/unit/interpreter/function-t.test.spec.ts | 154 - test/unit/interpreter/function-tan.spec.ts | 42 - test/unit/interpreter/function-tanh.spec.ts | 42 - .../unit/interpreter/function-tbilleq.spec.ts | 44 - .../interpreter/function-tbillprice.spec.ts | 40 - .../interpreter/function-tbillyield.spec.ts | 38 - test/unit/interpreter/function-tdist.spec.ts | 79 - test/unit/interpreter/function-text.spec.ts | 305 - test/unit/interpreter/function-time.spec.ts | 114 - .../interpreter/function-timevalue.spec.ts | 54 - test/unit/interpreter/function-today.spec.ts | 58 - test/unit/interpreter/function-trim.spec.ts | 41 - test/unit/interpreter/function-true.spec.ts | 18 - .../unit/interpreter/function-unichar.spec.ts | 74 - .../unit/interpreter/function-unicode.spec.ts | 81 - test/unit/interpreter/function-upper.spec.ts | 41 - test/unit/interpreter/function-var.p.spec.ts | 43 - test/unit/interpreter/function-var.s.spec.ts | 43 - test/unit/interpreter/function-vara.spec.ts | 43 - test/unit/interpreter/function-varpa.spec.ts | 43 - .../unit/interpreter/function-version.spec.ts | 98 - .../unit/interpreter/function-vlookup.spec.ts | 826 - .../unit/interpreter/function-weekday.spec.ts | 131 - .../unit/interpreter/function-weeknum.spec.ts | 145 - .../interpreter/function-weibull.dist.spec.ts | 65 - .../interpreter/function-workday.intl.spec.ts | 140 - .../unit/interpreter/function-workday.spec.ts | 79 - .../unit/interpreter/function-xlookup.spec.ts | 1276 - test/unit/interpreter/function-xnpv.spec.ts | 94 - test/unit/interpreter/function-xor.spec.ts | 123 - test/unit/interpreter/function-year.spec.ts | 52 - .../interpreter/function-yearfrac.spec.ts | 132 - test/unit/interpreter/function-z.test.spec.ts | 65 - test/unit/interpreter/matrix-plugin.spec.ts | 301 - test/unit/interpreter/nullvalue.spec.ts | 50 - test/unit/interpreter/number-literals.spec.ts | 66 - .../interpreter/operator-concatenate.spec.ts | 53 - .../interpreter/operator-division.spec.ts | 83 - test/unit/interpreter/operator-minus.spec.ts | 75 - .../unit/interpreter/operator-percent.spec.ts | 61 - test/unit/interpreter/operator-plus.spec.ts | 78 - test/unit/interpreter/operator-power.spec.ts | 100 - test/unit/interpreter/operator-times.spec.ts | 83 - .../interpreter/operator-unary-minus.spec.ts | 53 - .../interpreter/operator-unary-plus.spec.ts | 61 - test/unit/interpreter/paren-deps.spec.ts | 21 - test/unit/interpreter/precision.spec.ts | 290 - test/unit/interpreter/scalar.spec.ts | 34 - test/unit/interpreter/separate-cache.spec.ts | 17 - test/unit/interpreter/string-cmp.spec.ts | 144 - test/unit/licence.spec.ts | 18 - test/unit/matchers.spec.ts | 59 - test/unit/matrix-mapping.spec.ts | 59 - test/unit/matrix-size-check.spec.ts | 195 - test/unit/matrix.spec.ts | 303 - test/unit/named-expressions.spec.ts | 2176 -- test/unit/null-compatibility.spec.ts | 46 - test/unit/optional-parameters.spec.ts | 68 - test/unit/parser/apostrophe.spec.ts | 15 - test/unit/parser/boolean-operators.spec.ts | 72 - .../parser/cell-address-from-string.spec.ts | 62 - test/unit/parser/common.ts | 18 - .../unit/parser/compute-hash-from-ast.spec.ts | 223 - .../parser/compute-hash-from-tokens.spec.ts | 208 - test/unit/parser/concatenate-operator.spec.ts | 23 - test/unit/parser/decimal.spec.ts | 42 - test/unit/parser/error-literals.spec.ts | 62 - test/unit/parser/offset-translation.spec.ts | 214 - test/unit/parser/parser-caching.spec.ts | 24 - test/unit/parser/parser-dependencies.spec.ts | 121 - test/unit/parser/parser.spec.ts | 986 - test/unit/parser/percent-operator.spec.ts | 70 - test/unit/parser/range-offset.spec.ts | 51 - test/unit/parser/unparse.spec.ts | 612 - .../volatile-functions-detection.spec.ts | 63 - test/unit/parser/white-spaces.spec.ts | 163 - test/unit/range-mapping.spec.ts | 35 - test/unit/range-vertex.spec.ts | 45 - test/unit/ranges.spec.ts | 63 - test/unit/rebuild.spec.ts | 66 - test/unit/row-range.spec.ts | 74 - test/unit/scoped-namedExpressions.spec.ts | 32 - test/unit/serialization.spec.ts | 124 - test/unit/small-build.spec.ts | 25 - test/unit/small-setcellcontent.spec.ts | 32 - test/unit/statistics/statistics.spec.ts | 69 - test/unit/temporary-formulas.spec.ts | 151 - test/unit/testUtils.spec.ts | 10 - test/unit/testUtils.ts | 280 - test/unit/tsconfig.json | 22 - test/unit/type-inference.spec.ts | 350 - test/unit/undo-redo.spec.ts | 2575 -- test/unit/unsupported-types.spec.ts | 118 - test/unit/update-config.spec.ts | 125 - test/unit/volatile-functions.spec.ts | 59 - tsconfig.test.json | 13 - 527 files changed, 11300 insertions(+), 82958 deletions(-) delete mode 100644 .config/karma/base.js delete mode 100644 .config/karma/debug.js delete mode 100644 .github/codecov.yml delete mode 100644 .github/workflows/performance.yml delete mode 100644 .github/workflows/test.yml delete mode 100644 jasmine.json delete mode 100644 jest.config.js delete mode 100644 karma.conf.js delete mode 100644 karma.starter.ts delete mode 100644 test/compatibility/README.md delete mode 100644 test/compatibility/compare-evaluation-results.ts delete mode 100755 test/compatibility/test-compatibility.sh delete mode 100644 test/compatibility/test_data/basic-arithmetic.xlsx delete mode 100644 test/compatibility/test_data/logical-conditions.xlsx delete mode 100644 test/compatibility/test_data/lookup-basic.xlsx delete mode 100644 test/compatibility/test_data/sample_file.xlsx delete mode 100644 test/compatibility/test_data/text-functions.xlsx delete mode 100644 test/performance/basic-benchmark.ts delete mode 100644 test/performance/benchmark.ts delete mode 100644 test/performance/compare-benchmarks.ts delete mode 100644 test/performance/cruds-benchmark.ts delete mode 100644 test/performance/run-basic-benchmark.ts delete mode 100644 test/performance/run-cruds-benchmark.ts delete mode 100644 test/performance/sheets/05-sheet-t.ts delete mode 100644 test/performance/sheets/09-sheet-a.ts delete mode 100644 test/performance/sheets/10-sheet-b.ts delete mode 100644 test/performance/sheets/column-ranges.ts delete mode 100644 test/performance/utils/stats.ts delete mode 100644 test/performance/utils/utils.ts delete mode 100644 test/performance/write-to-file.ts delete mode 100644 test/unit/AbsoluteCellRange.spec.ts delete mode 100644 test/unit/CellContentParser.spec.ts delete mode 100644 test/unit/CellValueExporter.spec.ts delete mode 100644 test/unit/ColumnsSpan.spec.ts delete mode 100644 test/unit/RowsSpan.spec.ts delete mode 100644 test/unit/_setupFiles/babel.js delete mode 100644 test/unit/_setupFiles/bootstrap.ts delete mode 100644 test/unit/_setupFiles/globalSetup.ts delete mode 100644 test/unit/_setupFiles/jest/bootstrap.ts delete mode 100644 test/unit/_setupFiles/jest/toEqualError.ts delete mode 100644 test/unit/_setupFiles/jsdom.js delete mode 100644 test/unit/_setupFiles/matchers/index.ts delete mode 100644 test/unit/_setupFiles/matchers/toContainEqual.ts delete mode 100644 test/unit/_setupFiles/matchers/toEqualError.ts delete mode 100644 test/unit/_setupFiles/matchers/toMatchObject.ts delete mode 100644 test/unit/address-mapping.spec.ts delete mode 100644 test/unit/address-representation-converters.spec.ts delete mode 100644 test/unit/arrays-integration.spec.ts delete mode 100644 test/unit/arrays.spec.ts delete mode 100644 test/unit/build-engine.spec.ts delete mode 100644 test/unit/cache-order.spec.ts delete mode 100644 test/unit/column-index.spec.ts delete mode 100644 test/unit/column-range.spec.ts delete mode 100644 test/unit/computation-suspension.spec.ts delete mode 100644 test/unit/config.spec.ts delete mode 100644 test/unit/content-changes.spec.ts delete mode 100644 test/unit/criterion.spec.ts delete mode 100644 test/unit/crud-random.spec.ts delete mode 100644 test/unit/cruds/adding-columns-dependencies.spec.ts delete mode 100644 test/unit/cruds/adding-columns.spec.ts delete mode 100644 test/unit/cruds/adding-row-dependencies.spec.ts delete mode 100644 test/unit/cruds/adding-row.spec.ts delete mode 100644 test/unit/cruds/adding-sheet.spec.ts delete mode 100644 test/unit/cruds/batch-operations.spec.ts delete mode 100644 test/unit/cruds/change-cell-content.spec.ts delete mode 100644 test/unit/cruds/clear-sheet.spec.ts delete mode 100644 test/unit/cruds/copy-paste.spec.ts delete mode 100644 test/unit/cruds/cut-paste.spec.ts delete mode 100644 test/unit/cruds/move-cells.spec.ts delete mode 100644 test/unit/cruds/move-columns.spec.ts delete mode 100644 test/unit/cruds/move-rows.spec.ts delete mode 100644 test/unit/cruds/removing-columns.spec.ts delete mode 100644 test/unit/cruds/removing-rows.spec.ts delete mode 100644 test/unit/cruds/removing-sheet.spec.ts delete mode 100644 test/unit/cruds/rename-sheet.spec.ts delete mode 100644 test/unit/cruds/replace-sheet-content.spec.ts delete mode 100644 test/unit/cruds/set-column-order.spec.ts delete mode 100644 test/unit/cruds/set-matrix-empty.spec.ts delete mode 100644 test/unit/cruds/set-row-order.spec.ts delete mode 100644 test/unit/custom-functions.spec.ts delete mode 100644 test/unit/date.spec.ts delete mode 100644 test/unit/dependency-graph-sheet-reference-registrar.spec.ts delete mode 100644 test/unit/dependencyTransformers/clean-out-of-scope-dependencies-transformer.spec.ts delete mode 100644 test/unit/dependencyTransformers/combined-transformer.spec.ts delete mode 100644 test/unit/dependencyTransformers/remove-columns-transformer.spec.ts delete mode 100644 test/unit/dependencyTransformers/remove-rows-transformer.spec.ts delete mode 100644 test/unit/dependencyTransformers/transformer.spec.ts delete mode 100644 test/unit/dependent-formula-transformer.spec.ts delete mode 100644 test/unit/destruct.spec.ts delete mode 100644 test/unit/emitting-events.spec.ts delete mode 100644 test/unit/engine.spec.ts delete mode 100644 test/unit/error-address-preservation.spec.ts delete mode 100644 test/unit/escaping-support.spec.ts delete mode 100644 test/unit/extending-plugins.spec.ts delete mode 100644 test/unit/find-boundaries.spec.ts delete mode 100644 test/unit/format/format-interpreter.spec.ts delete mode 100644 test/unit/format/format-parser.spec.ts delete mode 100644 test/unit/functions-metadata.spec.ts delete mode 100644 test/unit/generate-cells-range.spec.ts delete mode 100644 test/unit/generatorUtils.spec.ts delete mode 100644 test/unit/graph-builder.spec.ts delete mode 100644 test/unit/graph-dependencies-queries.spec.ts delete mode 100644 test/unit/graph-garbage-collection.spec.ts delete mode 100644 test/unit/graph-vertex.spec.ts delete mode 100644 test/unit/graph.spec.ts delete mode 100644 test/unit/graphComparator.ts delete mode 100644 test/unit/helpers/licenseKeyValidator.spec.ts delete mode 100644 test/unit/i18n.spec.ts delete mode 100644 test/unit/interpreter.spec.ts delete mode 100644 test/unit/interpreter/aggregation-arguments.spec.ts delete mode 100644 test/unit/interpreter/aliases.spec.ts delete mode 100644 test/unit/interpreter/binary-search.spec.ts delete mode 100644 test/unit/interpreter/boolean-operators.spec.ts delete mode 100644 test/unit/interpreter/coercions.spec.ts delete mode 100644 test/unit/interpreter/criterion-computations.spec.ts delete mode 100644 test/unit/interpreter/cyclical-deps.spec.ts delete mode 100644 test/unit/interpreter/date-and-time-arithmetic.spec.ts delete mode 100644 test/unit/interpreter/error-literals.spec.ts delete mode 100644 test/unit/interpreter/function-abs.spec.ts delete mode 100644 test/unit/interpreter/function-acos.spec.ts delete mode 100644 test/unit/interpreter/function-acosh.spec.ts delete mode 100644 test/unit/interpreter/function-acot.spec.ts delete mode 100644 test/unit/interpreter/function-acoth.spec.ts delete mode 100644 test/unit/interpreter/function-address.spec.ts delete mode 100644 test/unit/interpreter/function-and.spec.ts delete mode 100644 test/unit/interpreter/function-arabic.spec.ts delete mode 100644 test/unit/interpreter/function-array_constrain.spec.ts delete mode 100644 test/unit/interpreter/function-arrayformula.spec.ts delete mode 100644 test/unit/interpreter/function-asin.spec.ts delete mode 100644 test/unit/interpreter/function-asinh.spec.ts delete mode 100644 test/unit/interpreter/function-atan.spec.ts delete mode 100644 test/unit/interpreter/function-atan2.spec.ts delete mode 100644 test/unit/interpreter/function-atanh.spec.ts delete mode 100644 test/unit/interpreter/function-avedev.spec.ts delete mode 100644 test/unit/interpreter/function-average.spec.ts delete mode 100644 test/unit/interpreter/function-averagea.spec.ts delete mode 100644 test/unit/interpreter/function-averageif.spec.ts delete mode 100644 test/unit/interpreter/function-base.spec.ts delete mode 100644 test/unit/interpreter/function-besseli.spec.ts delete mode 100644 test/unit/interpreter/function-besselj.spec.ts delete mode 100644 test/unit/interpreter/function-besselk.spec.ts delete mode 100644 test/unit/interpreter/function-bessely.spec.ts delete mode 100644 test/unit/interpreter/function-beta.dist.spec.ts delete mode 100644 test/unit/interpreter/function-beta.inv.spec.ts delete mode 100644 test/unit/interpreter/function-bin2dec.spec.ts delete mode 100644 test/unit/interpreter/function-bin2hex.spec.ts delete mode 100644 test/unit/interpreter/function-bin2oct.spec.ts delete mode 100644 test/unit/interpreter/function-binom.dist.spec.ts delete mode 100644 test/unit/interpreter/function-binom.inv.spec.ts delete mode 100644 test/unit/interpreter/function-bitand.spec.ts delete mode 100644 test/unit/interpreter/function-bitlshift.spec.ts delete mode 100644 test/unit/interpreter/function-bitor.spec.ts delete mode 100644 test/unit/interpreter/function-bitrshift.spec.ts delete mode 100644 test/unit/interpreter/function-bitxor.spec.ts delete mode 100644 test/unit/interpreter/function-ceiling.math.spec.ts delete mode 100644 test/unit/interpreter/function-ceiling.precise.spec.ts delete mode 100644 test/unit/interpreter/function-ceiling.spec.ts delete mode 100644 test/unit/interpreter/function-char.spec.ts delete mode 100644 test/unit/interpreter/function-chisq.dist.rt.spec.ts delete mode 100644 test/unit/interpreter/function-chisq.dist.spec.ts delete mode 100644 test/unit/interpreter/function-chisq.inv.rt.spec.ts delete mode 100644 test/unit/interpreter/function-chisq.inv.spec.ts delete mode 100644 test/unit/interpreter/function-chisq.test.spec.ts delete mode 100644 test/unit/interpreter/function-choose.spec.ts delete mode 100644 test/unit/interpreter/function-clean.spec.ts delete mode 100644 test/unit/interpreter/function-code.spec.ts delete mode 100644 test/unit/interpreter/function-column.spec.ts delete mode 100644 test/unit/interpreter/function-columns.spec.ts delete mode 100644 test/unit/interpreter/function-combin.spec.ts delete mode 100644 test/unit/interpreter/function-combina.spec.ts delete mode 100644 test/unit/interpreter/function-complex.spec.ts delete mode 100644 test/unit/interpreter/function-concatenate.spec.ts delete mode 100644 test/unit/interpreter/function-confidence.norm.spec.ts delete mode 100644 test/unit/interpreter/function-confidence.t.spec.ts delete mode 100644 test/unit/interpreter/function-correl.spec.ts delete mode 100644 test/unit/interpreter/function-cos.spec.ts delete mode 100644 test/unit/interpreter/function-cosh.spec.ts delete mode 100644 test/unit/interpreter/function-cot.spec.ts delete mode 100644 test/unit/interpreter/function-coth.spec.ts delete mode 100644 test/unit/interpreter/function-count.spec.ts delete mode 100644 test/unit/interpreter/function-counta.spec.ts delete mode 100644 test/unit/interpreter/function-countblank.spec.ts delete mode 100644 test/unit/interpreter/function-countif.spec.ts delete mode 100644 test/unit/interpreter/function-countifs.spec.ts delete mode 100644 test/unit/interpreter/function-countunique.spec.ts delete mode 100644 test/unit/interpreter/function-covariance.p.spec.ts delete mode 100644 test/unit/interpreter/function-covariance.s.spec.ts delete mode 100644 test/unit/interpreter/function-csc.spec.ts delete mode 100644 test/unit/interpreter/function-csch.spec.ts delete mode 100644 test/unit/interpreter/function-cumimpt.spec.ts delete mode 100644 test/unit/interpreter/function-cumprinc.spec.ts delete mode 100644 test/unit/interpreter/function-date.spec.ts delete mode 100644 test/unit/interpreter/function-datedif.spec.ts delete mode 100644 test/unit/interpreter/function-datevalue.spec.ts delete mode 100644 test/unit/interpreter/function-day.spec.ts delete mode 100644 test/unit/interpreter/function-days.spec.ts delete mode 100644 test/unit/interpreter/function-days360.spec.ts delete mode 100644 test/unit/interpreter/function-db.spec.ts delete mode 100644 test/unit/interpreter/function-ddb.spec.ts delete mode 100644 test/unit/interpreter/function-dec2bin.spec.ts delete mode 100644 test/unit/interpreter/function-dec2hex.spec.ts delete mode 100644 test/unit/interpreter/function-dec2oct.spec.ts delete mode 100644 test/unit/interpreter/function-decimal.spec.ts delete mode 100644 test/unit/interpreter/function-degrees.spec.ts delete mode 100644 test/unit/interpreter/function-delta.spec.ts delete mode 100644 test/unit/interpreter/function-devsq.spec.ts delete mode 100644 test/unit/interpreter/function-dollarde.spec.ts delete mode 100644 test/unit/interpreter/function-dollarfr.spec.ts delete mode 100644 test/unit/interpreter/function-edate.spec.ts delete mode 100644 test/unit/interpreter/function-effect.spec.ts delete mode 100644 test/unit/interpreter/function-eomonth.spec.ts delete mode 100644 test/unit/interpreter/function-erf.spec.ts delete mode 100644 test/unit/interpreter/function-erfc.spec.ts delete mode 100644 test/unit/interpreter/function-even.spec.ts delete mode 100644 test/unit/interpreter/function-exact.spec.ts delete mode 100644 test/unit/interpreter/function-exp.spec.ts delete mode 100644 test/unit/interpreter/function-expon.dist.spec.ts delete mode 100644 test/unit/interpreter/function-f.dist.rt.spec.ts delete mode 100644 test/unit/interpreter/function-f.dist.spec.ts delete mode 100644 test/unit/interpreter/function-f.inv.rt.spec.ts delete mode 100644 test/unit/interpreter/function-f.inv.spec.ts delete mode 100644 test/unit/interpreter/function-f.test.spec.ts delete mode 100644 test/unit/interpreter/function-fact.spec.ts delete mode 100644 test/unit/interpreter/function-factdouble.spec.ts delete mode 100644 test/unit/interpreter/function-false.spec.ts delete mode 100644 test/unit/interpreter/function-filter.spec.ts delete mode 100644 test/unit/interpreter/function-find.spec.ts delete mode 100644 test/unit/interpreter/function-fisher.spec.ts delete mode 100644 test/unit/interpreter/function-fisherinv.spec.ts delete mode 100644 test/unit/interpreter/function-floor.math.spec.ts delete mode 100644 test/unit/interpreter/function-floor.precise.spec.ts delete mode 100644 test/unit/interpreter/function-floor.spec.ts delete mode 100644 test/unit/interpreter/function-formulatext.spec.ts delete mode 100644 test/unit/interpreter/function-fv.spec.ts delete mode 100644 test/unit/interpreter/function-fvschedule.spec.ts delete mode 100644 test/unit/interpreter/function-gamma.dist.spec.ts delete mode 100644 test/unit/interpreter/function-gamma.inv.spec.ts delete mode 100644 test/unit/interpreter/function-gamma.spec.ts delete mode 100644 test/unit/interpreter/function-gammaln.spec.ts delete mode 100644 test/unit/interpreter/function-gauss.spec.ts delete mode 100644 test/unit/interpreter/function-gcd.spec.ts delete mode 100644 test/unit/interpreter/function-geomean.spec.ts delete mode 100644 test/unit/interpreter/function-harmean.spec.ts delete mode 100644 test/unit/interpreter/function-hex2bin.spec.ts delete mode 100644 test/unit/interpreter/function-hex2dec.spec.ts delete mode 100644 test/unit/interpreter/function-hex2oct.spec.ts delete mode 100644 test/unit/interpreter/function-hfadd.spec.ts delete mode 100644 test/unit/interpreter/function-hfconcat.spec.ts delete mode 100644 test/unit/interpreter/function-hfdivide.spec.ts delete mode 100644 test/unit/interpreter/function-hfeq.spec.ts delete mode 100644 test/unit/interpreter/function-hfgt.spec.ts delete mode 100644 test/unit/interpreter/function-hfgte.spec.ts delete mode 100644 test/unit/interpreter/function-hflt.spec.ts delete mode 100644 test/unit/interpreter/function-hflte.spec.ts delete mode 100644 test/unit/interpreter/function-hfminus.spec.ts delete mode 100644 test/unit/interpreter/function-hfmultiply.spec.ts delete mode 100644 test/unit/interpreter/function-hfne.spec.ts delete mode 100644 test/unit/interpreter/function-hfpow.spec.ts delete mode 100644 test/unit/interpreter/function-hfuminus.spec.ts delete mode 100644 test/unit/interpreter/function-hfunary_percent.spec.ts delete mode 100644 test/unit/interpreter/function-hfuplus.spec.ts delete mode 100644 test/unit/interpreter/function-hlookup.spec.ts delete mode 100644 test/unit/interpreter/function-hour.spec.ts delete mode 100644 test/unit/interpreter/function-hyperlink.spec.ts delete mode 100644 test/unit/interpreter/function-hypgeom.dist.spec.ts delete mode 100644 test/unit/interpreter/function-if.spec.ts delete mode 100644 test/unit/interpreter/function-iferror.spec.ts delete mode 100644 test/unit/interpreter/function-ifna.spec.ts delete mode 100644 test/unit/interpreter/function-ifs.spec.ts delete mode 100644 test/unit/interpreter/function-imabs.spec.ts delete mode 100644 test/unit/interpreter/function-imaginary.spec.ts delete mode 100644 test/unit/interpreter/function-imargument.spec.ts delete mode 100644 test/unit/interpreter/function-imconjugate.spec.ts delete mode 100644 test/unit/interpreter/function-imcos.spec.ts delete mode 100644 test/unit/interpreter/function-imcosh.spec.ts delete mode 100644 test/unit/interpreter/function-imcot.spec.ts delete mode 100644 test/unit/interpreter/function-imcsc.spec.ts delete mode 100644 test/unit/interpreter/function-imcsch.spec.ts delete mode 100644 test/unit/interpreter/function-imdiv.spec.ts delete mode 100644 test/unit/interpreter/function-imexp.spec.ts delete mode 100644 test/unit/interpreter/function-imln.spec.ts delete mode 100644 test/unit/interpreter/function-imlog10.spec.ts delete mode 100644 test/unit/interpreter/function-imlog2.spec.ts delete mode 100644 test/unit/interpreter/function-impower.spec.ts delete mode 100644 test/unit/interpreter/function-improduct.spec.ts delete mode 100644 test/unit/interpreter/function-imreal.spec.ts delete mode 100644 test/unit/interpreter/function-imsec.spec.ts delete mode 100644 test/unit/interpreter/function-imsech.spec.ts delete mode 100644 test/unit/interpreter/function-imsin.spec.ts delete mode 100644 test/unit/interpreter/function-imsinh.spec.ts delete mode 100644 test/unit/interpreter/function-imsqrt.spec.ts delete mode 100644 test/unit/interpreter/function-imsub.spec.ts delete mode 100644 test/unit/interpreter/function-imsum.spec.ts delete mode 100644 test/unit/interpreter/function-imtan.spec.ts delete mode 100644 test/unit/interpreter/function-index.spec.ts delete mode 100644 test/unit/interpreter/function-int.spec.ts delete mode 100644 test/unit/interpreter/function-interval.spec.ts delete mode 100644 test/unit/interpreter/function-ipmt.spec.ts delete mode 100644 test/unit/interpreter/function-isbinary.spec.ts delete mode 100644 test/unit/interpreter/function-isblank.spec.ts delete mode 100644 test/unit/interpreter/function-iserr.spec.ts delete mode 100644 test/unit/interpreter/function-iserror.spec.ts delete mode 100644 test/unit/interpreter/function-iseven.spec.ts delete mode 100644 test/unit/interpreter/function-isformula.spec.ts delete mode 100644 test/unit/interpreter/function-islogical.spec.ts delete mode 100644 test/unit/interpreter/function-isna.spec.ts delete mode 100644 test/unit/interpreter/function-isnontext.spec.ts delete mode 100644 test/unit/interpreter/function-isnumber.spec.ts delete mode 100644 test/unit/interpreter/function-isodd.spec.ts delete mode 100644 test/unit/interpreter/function-isoweeknum.spec.ts delete mode 100644 test/unit/interpreter/function-ispmt.spec.ts delete mode 100644 test/unit/interpreter/function-isref.spec.ts delete mode 100644 test/unit/interpreter/function-istext.spec.ts delete mode 100644 test/unit/interpreter/function-large.spec.ts delete mode 100644 test/unit/interpreter/function-lcm.spec.ts delete mode 100644 test/unit/interpreter/function-left.spec.ts delete mode 100644 test/unit/interpreter/function-len.spec.ts delete mode 100644 test/unit/interpreter/function-ln.spec.ts delete mode 100644 test/unit/interpreter/function-log.spec.ts delete mode 100644 test/unit/interpreter/function-log10.spec.ts delete mode 100644 test/unit/interpreter/function-lognorm.dist.spec.ts delete mode 100644 test/unit/interpreter/function-lognorm.inv.spec.ts delete mode 100644 test/unit/interpreter/function-lower.spec.ts delete mode 100644 test/unit/interpreter/function-match.spec.ts delete mode 100644 test/unit/interpreter/function-max.spec.ts delete mode 100644 test/unit/interpreter/function-maxa.spec.ts delete mode 100644 test/unit/interpreter/function-maxifs.spec.ts delete mode 100644 test/unit/interpreter/function-median.spec.ts delete mode 100644 test/unit/interpreter/function-mid.spec.ts delete mode 100644 test/unit/interpreter/function-min.spec.ts delete mode 100644 test/unit/interpreter/function-mina.spec.ts delete mode 100644 test/unit/interpreter/function-minifs.spec.ts delete mode 100644 test/unit/interpreter/function-minute.spec.ts delete mode 100644 test/unit/interpreter/function-mirr.spec.ts delete mode 100644 test/unit/interpreter/function-modulo.spec.ts delete mode 100644 test/unit/interpreter/function-month.spec.ts delete mode 100644 test/unit/interpreter/function-mround.spec.ts delete mode 100644 test/unit/interpreter/function-multinomial.spec.ts delete mode 100644 test/unit/interpreter/function-na.spec.ts delete mode 100644 test/unit/interpreter/function-negbinom.dist.spec.ts delete mode 100644 test/unit/interpreter/function-networkdays.intl.spec.ts delete mode 100644 test/unit/interpreter/function-networkdays.spec.ts delete mode 100644 test/unit/interpreter/function-nominal.spec.ts delete mode 100644 test/unit/interpreter/function-norm.dist.spec.ts delete mode 100644 test/unit/interpreter/function-norm.inv.spec.ts delete mode 100644 test/unit/interpreter/function-norm.s.dist.spec.ts delete mode 100644 test/unit/interpreter/function-norm.s.inv.spec.ts delete mode 100644 test/unit/interpreter/function-not.spec.ts delete mode 100644 test/unit/interpreter/function-now.spec.ts delete mode 100644 test/unit/interpreter/function-nper.spec.ts delete mode 100644 test/unit/interpreter/function-npv.spec.ts delete mode 100644 test/unit/interpreter/function-oct2bin.spec.ts delete mode 100644 test/unit/interpreter/function-oct2dec.spec.ts delete mode 100644 test/unit/interpreter/function-oct2hex.spec.ts delete mode 100644 test/unit/interpreter/function-odd.spec.ts delete mode 100644 test/unit/interpreter/function-or.spec.ts delete mode 100644 test/unit/interpreter/function-pduration.spec.ts delete mode 100644 test/unit/interpreter/function-phi.spec.ts delete mode 100644 test/unit/interpreter/function-pi.spec.ts delete mode 100644 test/unit/interpreter/function-pmt.spec.ts delete mode 100644 test/unit/interpreter/function-poisson.dist.spec.ts delete mode 100644 test/unit/interpreter/function-power.spec.ts delete mode 100644 test/unit/interpreter/function-ppmt.spec.ts delete mode 100644 test/unit/interpreter/function-product.spec.ts delete mode 100644 test/unit/interpreter/function-proper.spec.ts delete mode 100644 test/unit/interpreter/function-pv.spec.ts delete mode 100644 test/unit/interpreter/function-quotient.spec.ts delete mode 100644 test/unit/interpreter/function-radians.spec.ts delete mode 100644 test/unit/interpreter/function-rand.spec.ts delete mode 100644 test/unit/interpreter/function-randbetween.spec.ts delete mode 100644 test/unit/interpreter/function-rate.spec.ts delete mode 100644 test/unit/interpreter/function-replace.spec.ts delete mode 100644 test/unit/interpreter/function-rept.spec.ts delete mode 100644 test/unit/interpreter/function-right.spec.ts delete mode 100644 test/unit/interpreter/function-roman.spec.ts delete mode 100644 test/unit/interpreter/function-round.spec.ts delete mode 100644 test/unit/interpreter/function-rounddown.spec.ts delete mode 100644 test/unit/interpreter/function-roundup.spec.ts delete mode 100644 test/unit/interpreter/function-row.spec.ts delete mode 100644 test/unit/interpreter/function-rows.spec.ts delete mode 100644 test/unit/interpreter/function-rri.spec.ts delete mode 100644 test/unit/interpreter/function-rsq.spec.ts delete mode 100644 test/unit/interpreter/function-search.spec.ts delete mode 100644 test/unit/interpreter/function-sec.spec.ts delete mode 100644 test/unit/interpreter/function-sech.spec.ts delete mode 100644 test/unit/interpreter/function-second.spec.ts delete mode 100644 test/unit/interpreter/function-seriessum.spec.ts delete mode 100644 test/unit/interpreter/function-sheet.spec.ts delete mode 100644 test/unit/interpreter/function-sheets.spec.ts delete mode 100644 test/unit/interpreter/function-sign.spec.ts delete mode 100644 test/unit/interpreter/function-sin.spec.ts delete mode 100644 test/unit/interpreter/function-sinh.spec.ts delete mode 100644 test/unit/interpreter/function-skew.p.spec.ts delete mode 100644 test/unit/interpreter/function-skew.spec.ts delete mode 100644 test/unit/interpreter/function-sln.spec.ts delete mode 100644 test/unit/interpreter/function-slope.spec.ts delete mode 100644 test/unit/interpreter/function-small.spec.ts delete mode 100644 test/unit/interpreter/function-split.spec.ts delete mode 100644 test/unit/interpreter/function-sqrt.spec.ts delete mode 100644 test/unit/interpreter/function-sqrtpi.spec.ts delete mode 100644 test/unit/interpreter/function-standardize.spec.ts delete mode 100644 test/unit/interpreter/function-stdev.p.spec.ts delete mode 100644 test/unit/interpreter/function-stdev.s.spec.ts delete mode 100644 test/unit/interpreter/function-stdeva.spec.ts delete mode 100644 test/unit/interpreter/function-stdevpa.spec.ts delete mode 100644 test/unit/interpreter/function-steyx.spec.ts delete mode 100644 test/unit/interpreter/function-substitute.spec.ts delete mode 100644 test/unit/interpreter/function-subtotal.spec.ts delete mode 100644 test/unit/interpreter/function-sum.spec.ts delete mode 100644 test/unit/interpreter/function-sumif.spec.ts delete mode 100644 test/unit/interpreter/function-sumproduct.spec.ts delete mode 100644 test/unit/interpreter/function-sumsq.spec.ts delete mode 100644 test/unit/interpreter/function-sumx2my2.spec.ts delete mode 100644 test/unit/interpreter/function-sumx2py2.spec.ts delete mode 100644 test/unit/interpreter/function-sumxmy2.spec.ts delete mode 100644 test/unit/interpreter/function-switch.spec.ts delete mode 100644 test/unit/interpreter/function-syd.spec.ts delete mode 100644 test/unit/interpreter/function-t.dist.2t.spec.ts delete mode 100644 test/unit/interpreter/function-t.dist.rt.spec.ts delete mode 100644 test/unit/interpreter/function-t.dist.spec.ts delete mode 100644 test/unit/interpreter/function-t.inv.2t.spec.ts delete mode 100644 test/unit/interpreter/function-t.inv.spec.ts delete mode 100644 test/unit/interpreter/function-t.spec.ts delete mode 100644 test/unit/interpreter/function-t.test.spec.ts delete mode 100644 test/unit/interpreter/function-tan.spec.ts delete mode 100644 test/unit/interpreter/function-tanh.spec.ts delete mode 100644 test/unit/interpreter/function-tbilleq.spec.ts delete mode 100644 test/unit/interpreter/function-tbillprice.spec.ts delete mode 100644 test/unit/interpreter/function-tbillyield.spec.ts delete mode 100644 test/unit/interpreter/function-tdist.spec.ts delete mode 100644 test/unit/interpreter/function-text.spec.ts delete mode 100644 test/unit/interpreter/function-time.spec.ts delete mode 100644 test/unit/interpreter/function-timevalue.spec.ts delete mode 100644 test/unit/interpreter/function-today.spec.ts delete mode 100644 test/unit/interpreter/function-trim.spec.ts delete mode 100644 test/unit/interpreter/function-true.spec.ts delete mode 100644 test/unit/interpreter/function-unichar.spec.ts delete mode 100644 test/unit/interpreter/function-unicode.spec.ts delete mode 100644 test/unit/interpreter/function-upper.spec.ts delete mode 100644 test/unit/interpreter/function-var.p.spec.ts delete mode 100644 test/unit/interpreter/function-var.s.spec.ts delete mode 100644 test/unit/interpreter/function-vara.spec.ts delete mode 100644 test/unit/interpreter/function-varpa.spec.ts delete mode 100644 test/unit/interpreter/function-version.spec.ts delete mode 100644 test/unit/interpreter/function-vlookup.spec.ts delete mode 100644 test/unit/interpreter/function-weekday.spec.ts delete mode 100644 test/unit/interpreter/function-weeknum.spec.ts delete mode 100644 test/unit/interpreter/function-weibull.dist.spec.ts delete mode 100644 test/unit/interpreter/function-workday.intl.spec.ts delete mode 100644 test/unit/interpreter/function-workday.spec.ts delete mode 100644 test/unit/interpreter/function-xlookup.spec.ts delete mode 100644 test/unit/interpreter/function-xnpv.spec.ts delete mode 100644 test/unit/interpreter/function-xor.spec.ts delete mode 100644 test/unit/interpreter/function-year.spec.ts delete mode 100644 test/unit/interpreter/function-yearfrac.spec.ts delete mode 100644 test/unit/interpreter/function-z.test.spec.ts delete mode 100644 test/unit/interpreter/matrix-plugin.spec.ts delete mode 100644 test/unit/interpreter/nullvalue.spec.ts delete mode 100644 test/unit/interpreter/number-literals.spec.ts delete mode 100644 test/unit/interpreter/operator-concatenate.spec.ts delete mode 100644 test/unit/interpreter/operator-division.spec.ts delete mode 100644 test/unit/interpreter/operator-minus.spec.ts delete mode 100644 test/unit/interpreter/operator-percent.spec.ts delete mode 100644 test/unit/interpreter/operator-plus.spec.ts delete mode 100644 test/unit/interpreter/operator-power.spec.ts delete mode 100644 test/unit/interpreter/operator-times.spec.ts delete mode 100644 test/unit/interpreter/operator-unary-minus.spec.ts delete mode 100644 test/unit/interpreter/operator-unary-plus.spec.ts delete mode 100644 test/unit/interpreter/paren-deps.spec.ts delete mode 100644 test/unit/interpreter/precision.spec.ts delete mode 100644 test/unit/interpreter/scalar.spec.ts delete mode 100644 test/unit/interpreter/separate-cache.spec.ts delete mode 100644 test/unit/interpreter/string-cmp.spec.ts delete mode 100644 test/unit/licence.spec.ts delete mode 100644 test/unit/matchers.spec.ts delete mode 100644 test/unit/matrix-mapping.spec.ts delete mode 100644 test/unit/matrix-size-check.spec.ts delete mode 100644 test/unit/matrix.spec.ts delete mode 100644 test/unit/named-expressions.spec.ts delete mode 100644 test/unit/null-compatibility.spec.ts delete mode 100644 test/unit/optional-parameters.spec.ts delete mode 100644 test/unit/parser/apostrophe.spec.ts delete mode 100644 test/unit/parser/boolean-operators.spec.ts delete mode 100644 test/unit/parser/cell-address-from-string.spec.ts delete mode 100644 test/unit/parser/common.ts delete mode 100644 test/unit/parser/compute-hash-from-ast.spec.ts delete mode 100644 test/unit/parser/compute-hash-from-tokens.spec.ts delete mode 100644 test/unit/parser/concatenate-operator.spec.ts delete mode 100644 test/unit/parser/decimal.spec.ts delete mode 100644 test/unit/parser/error-literals.spec.ts delete mode 100644 test/unit/parser/offset-translation.spec.ts delete mode 100644 test/unit/parser/parser-caching.spec.ts delete mode 100644 test/unit/parser/parser-dependencies.spec.ts delete mode 100644 test/unit/parser/parser.spec.ts delete mode 100644 test/unit/parser/percent-operator.spec.ts delete mode 100644 test/unit/parser/range-offset.spec.ts delete mode 100644 test/unit/parser/unparse.spec.ts delete mode 100644 test/unit/parser/volatile-functions-detection.spec.ts delete mode 100644 test/unit/parser/white-spaces.spec.ts delete mode 100644 test/unit/range-mapping.spec.ts delete mode 100644 test/unit/range-vertex.spec.ts delete mode 100644 test/unit/ranges.spec.ts delete mode 100644 test/unit/rebuild.spec.ts delete mode 100644 test/unit/row-range.spec.ts delete mode 100644 test/unit/scoped-namedExpressions.spec.ts delete mode 100644 test/unit/serialization.spec.ts delete mode 100644 test/unit/small-build.spec.ts delete mode 100644 test/unit/small-setcellcontent.spec.ts delete mode 100644 test/unit/statistics/statistics.spec.ts delete mode 100644 test/unit/temporary-formulas.spec.ts delete mode 100644 test/unit/testUtils.spec.ts delete mode 100644 test/unit/testUtils.ts delete mode 100644 test/unit/tsconfig.json delete mode 100644 test/unit/type-inference.spec.ts delete mode 100644 test/unit/undo-redo.spec.ts delete mode 100644 test/unit/unsupported-types.spec.ts delete mode 100644 test/unit/update-config.spec.ts delete mode 100644 test/unit/volatile-functions.spec.ts delete mode 100644 tsconfig.test.json diff --git a/.config/karma/base.js b/.config/karma/base.js deleted file mode 100644 index d66811a35f..0000000000 --- a/.config/karma/base.js +++ /dev/null @@ -1,80 +0,0 @@ -const webpackConfigFactory = require('../../webpack.config'); - -module.exports.create = function(config) { - return { - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - - client: { - clearContext: false, - spec: config.spec - }, - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine'], - - // list of files / patterns to load in the browser - files: [ - 'karma.starter.ts', - ], - - // list of files / patterns to exclude - exclude: [ ], - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - 'karma.starter.ts': ['webpack', 'sourcemap'], - }, - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['dots'], - - // web server port - port: 9876, - - // enable / disable colors in the output (reporters and logs) - colors: true, - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['ChromeHeadless', 'FirefoxHeadless'], - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: true, - - // Concurrency level - // how many browser should be started simultaneous - concurrency: Infinity, - - // Extending timeout fixes https://github.com/handsontable/hyperformula/issues/1430 - browserDisconnectTimeout : 60000, - - // Webpack's configuration for Karma - webpack: (function() { - // Take the second config from an array - full HF build. - const config = webpackConfigFactory('development')[1]; - - // Loaders are executed from bottom to top. Push ts-loader as a first loader. - config.module.rules[0].use.push({ - loader: 'ts-loader', - options: { - configFile: 'tsconfig.test.json' - } - }); - - return config; - }()), - }; -}; diff --git a/.config/karma/debug.js b/.config/karma/debug.js deleted file mode 100644 index e6c9fe092c..0000000000 --- a/.config/karma/debug.js +++ /dev/null @@ -1,13 +0,0 @@ -const configFactory = require('./base'); - -module.exports.create = function(config) { - const configBase = configFactory.create(config); - - return { - ...configBase, - browsers: ['Chrome'], - reporters: ['kjhtml'], - singleRun: false, - autoWatch: true, - } -} diff --git a/.eslintignore b/.eslintignore index 37928812fe..1639cebad7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,20 +9,15 @@ src/interpreter/plugin/3rdparty # Configurations *.config.js -karma.* doc -test/unit/_setupFiles/*.js # Auto-generated directories commonjs -coverage dist doc es languages lib script -test-jasmine -test-jest typedoc typings diff --git a/.eslintrc.js b/.eslintrc.js index 27fe09a0cd..5727783ac3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,16 +6,12 @@ module.exports = { '@typescript-eslint', 'license-header', 'jsdoc', - 'jasmine', - 'jest', ], env: { - jasmine: true, - 'jest/globals': true, }, parserOptions: { tsconfigRootDir: __dirname, - project: './tsconfig.test.json', + project: './tsconfig.json', createDefaultProgram: true, }, extends: [ @@ -23,9 +19,6 @@ module.exports = { 'plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', - 'plugin:jasmine/recommended', - 'plugin:jest/recommended', - 'plugin:jest/style', ], rules: { // Automatic fixers @@ -122,13 +115,6 @@ module.exports = { MethodDefinition: true, } }], - 'jest/no-jasmine-globals': 'off', - 'jest/no-alias-methods': 'off', - 'jest/no-conditional-expect': 'warn', - 'jest/no-standalone-expect': 'warn', - 'jest/no-test-prefixes': 'off', - 'jest/prefer-to-be': 'warn', - 'jest/prefer-to-have-length': 'off', }, overrides: [ { @@ -143,11 +129,5 @@ module.exports = { 'sort-keys': ['error', 'asc'], } }, - { - files: ['**/*.spec.ts'], - rules: { - '@typescript-eslint/no-non-null-assertion': 'off', - } - } ], } diff --git a/.github/codecov.yml b/.github/codecov.yml deleted file mode 100644 index d0bd2428bd..0000000000 --- a/.github/codecov.yml +++ /dev/null @@ -1,14 +0,0 @@ -codecov: - require_ci_to_pass: yes - -coverage: - range: 95..100 - round: down - precision: 2 - -comment: - layout: "reach, diff, flags, files" - behavior: new - require_changes: false - require_base: yes - require_head: yes diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml deleted file mode 100644 index f70b6b37de..0000000000 --- a/.github/workflows/performance.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Performance -permissions: - contents: read - pull-requests: write - -on: - pull_request: - types: - - opened - - reopened - - synchronize # the head branch is updated from the base branch, new commits are pushed to the head branch, or the base branch is changed - -jobs: - performance-test: - strategy: - matrix: - node-version: [ '22' ] - os: [ 'ubuntu-latest' ] - name: Test performance - runs-on: ${{ matrix.os }} - steps: - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@56899e050abffc08c2b3b61f3ec6a79a9dc3223d # https://github.com/actions/setup-node/releases/tag/v1.4.4 - with: - node-version: ${{ matrix.node-version }} - - - name: (base) Checkout - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # https://github.com/actions/checkout/releases/tag/v2.3.4 - with: - ref: ${{ github.event.pull_request.base.sha }} - - - name: (base) Install dependencies - run: | - npm ci - - - name: (base) Run performance tests - run: | - npm run benchmark:write-to-file base.json - - - name: (head) Checkout - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # https://github.com/actions/checkout/releases/tag/v2.3.4 - with: - clean: false - - - name: (head) Install dependencies - run: | - npm ci - - - name: (head) Run performance tests - run: | - npm run benchmark:write-to-file head.json - - - name: Compare the results - run: | - npm run benchmark:compare-benchmarks base.json head.json performance-report.md - - - name: Publish a comment - header - uses: marocchino/sticky-pull-request-comment@6804b5ad49d19c10c9ae7cf5057352f7ff333f31 # https://github.com/marocchino/sticky-pull-request-comment/tree/v1.6.0 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - message: | - ## Performance comparison of head (${{ github.event.pull_request.head.sha }}) vs base (${{ github.event.pull_request.base.sha }}) - - - name: Publish a comment - performance comparison report - uses: marocchino/sticky-pull-request-comment@6804b5ad49d19c10c9ae7cf5057352f7ff333f31 # https://github.com/marocchino/sticky-pull-request-comment/tree/v1.6.0 - with: - append: true - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - path: performance-report.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 51a87c303c..0000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Test -permissions: - contents: read - -on: - pull_request: - types: - - opened - - reopened - - synchronize # the head branch is updated from the base branch, new commits are pushed to the head branch, or the base branch is changed - push: - branches: - - 'master' - - 'develop' - - 'release/**' - -jobs: - unit-tests: - strategy: - matrix: - node-version: [ '22' ] - os: [ 'ubuntu-latest' ] - name: unit-tests - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598 # https://github.com/actions/checkout/releases/tag/v2.0.0 - - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@56899e050abffc08c2b3b61f3ec6a79a9dc3223d # https://github.com/actions/setup-node/releases/tag/v1.4.4 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: | - npm ci - - - name: Run tests - run: | - npm run test:unit.ci -- --coverage - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@6004246f47ab62d32be025ce173b241cd84ac58e # https://github.com/codecov/codecov-action/releases/tag/v1.0.13 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - - browser-tests: - strategy: - matrix: - node-version: [ '22' ] - os: [ 'ubuntu-latest' ] - name: browser-tests - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@722adc63f1aa60a57ec37892e133b1d319cae598 # https://github.com/actions/checkout/releases/tag/v2.0.0 - - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@56899e050abffc08c2b3b61f3ec6a79a9dc3223d # https://github.com/actions/setup-node/releases/tag/v1.4.4 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: | - npm ci - - - name: Run tests - run: | - npm run test:browser diff --git a/.gitignore b/.gitignore index d4bb1b0997..65a386ec94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .idea/ .vscode /commonjs/ -/coverage/ /dist/ /doc/ /docs/api/ @@ -13,8 +12,6 @@ /es/ /languages/ /lib/ -/test-jasmine/ -/test-jest/ node_modules/ /typings/ /storage/ diff --git a/.typedoc.ts b/.typedoc.ts index 0001ced876..8f2e9dba7b 100644 --- a/.typedoc.ts +++ b/.typedoc.ts @@ -1,6 +1,5 @@ module.exports = { "exclude": [ - "./test/**", "./src/interpreter/**", "./src/i18n/**", "./src/parser/**", diff --git a/Makefile b/Makefile index ea1c9af8db..73b87a5faa 100644 --- a/Makefile +++ b/Makefile @@ -7,18 +7,9 @@ setup: ## Setup project compile: ## Compile to javascript @npm run compile -test: ## Run tests - @npm run test +check: typecheck lint ## Check whether code is working correctly (types + lint) -unit: ## Run unit tests - @npm run test:unit - -test-ci: ## Separate test configuration for CI environment - @npm run test - -check: typecheck test ## Check whether code is working correctly (types + specs) - -full: check lint-fix ## Check whether code is ready to commit (types + specs + lint) +full: check lint-fix ## Check whether code is ready to commit (types + lint) lint: ## Show linting errors @npm run lint @@ -26,9 +17,6 @@ lint: ## Show linting errors lint-fix: ## Fix linting errors @npm run lint:fix -coverage: ## Run tests and show coverage - @npm run test:coverage - doc: ## Generate documentation @npm run typedoc:build @@ -65,6 +53,6 @@ verify-production-licenses: help: ## Show all make commands @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -.PHONY: test coverage benchmark doc servedoc +.PHONY: doc servedoc .DEFAULT_GOAL := help diff --git a/docs/guide/building.md b/docs/guide/building.md index a781b05b8b..7e21c283d4 100644 --- a/docs/guide/building.md +++ b/docs/guide/building.md @@ -60,22 +60,6 @@ Most likely, you will want to document the code. You can use the following comma * `npm run docs:build` - builds the docs * `npm run docs:dev` - serves the development version of the docs locally -## Run the tests - -The tests are done with Jest and Karma. The same test suite should -pass in both of them because the library might be used -[server-side](server-side-installation) or in a browser, so you have -to be sure that both environments are fine. - -* `npm run test` - runs the linter and all tests -* `npm run test:unit` - runs unit tests - * To run a test suite that matches a word, add a Jest `-t` flag. For example: `npm run test:unit -- -t 'SUMIF'` runs only the tests that match the word `SUMIF` within `describe()` or `it()`. - * To run a specific test suite, pass the file name. For example: `npm run test:unit 'function-sumif.spec.ts'` runs only the unit tests from the file `function-sumif.spec.ts`. -* `npm run test:coverage` - runs unit tests and generates code coverage -* `npm run test:browser` - runs tests in **karma** once and closes all open browsers - * To run a specific `spec` file or a test suite you can add a Karma `--spec` flag. For example: `npm run test:browser.debug -- --spec=matrix.spec.ts` runs `matrix.spec.ts` browser tests only -* `npm run test:browser.debug` - runs test in **karma** only in Chrome until you exit the process. It watches changes in `src` and `test` directories and rebuilds them automatically. - ## Run the linter You can use the following commands to lint the code, so it meets the required standards. ESLint is used as the tool of choice in this case. diff --git a/jasmine.json b/jasmine.json deleted file mode 100644 index bb08a6049d..0000000000 --- a/jasmine.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "spec_dir": "test-jasmine/test", - "spec_files": [ - "**/*[sS]pec.js" - ], - "helpers": [ - "_setupFiles/babel.js", - "_setupFiles/bootstrap.js", - "_setupFiles/jsdom.js" - ], - "stopSpecOnExpectationFailure": false, - "random": true -} diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index f7573a049b..0000000000 --- a/jest.config.js +++ /dev/null @@ -1,60 +0,0 @@ -// For a detailed explanation regarding each configuration property, visit: -// https://jestjs.io/docs/en/configuration.html - -module.exports = { - // An array of glob patterns indicating a set of files for which coverage information should be collected - collectCoverageFrom: [ - 'src/**', - '!**/node_modules/**', - ], - - coverageProvider: 'babel', - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // A path to a module which exports an async function that is triggered once before all test suites - globalSetup: '/test/unit/_setupFiles/globalSetup.ts', - - // A set of global variables that need to be available in all test environments - globals: { - "ts-jest": { - "tsconfig": "./test/unit/tsconfig.json" - } - }, - - // An array of file extensions your modules use - moduleFileExtensions: [ - "ts", - "tsx", - "js" - ], - - // The paths to modules that run some code to configure or set up the testing environment after each test - setupFilesAfterEnv: [ - '/test/unit/_setupFiles/bootstrap.ts', - '/test/unit/_setupFiles/jest/bootstrap.ts' - ], - - // The test environment that will be used for testing - testEnvironment: "node", - - // The glob patterns Jest uses to detect test files - testMatch: [ - "/test/unit/**/*spec.(ts|js)" - ], - - silent: true, - - // A map from regular expressions to paths to transformers - transform: { - "^.+\\.(ts|tsx)$": "ts-jest" - }, - - watchPathIgnorePatterns: [ - '/node_modules/', - '/dist/', - '/commonjs/', - '/es/', - ] -}; diff --git a/karma.conf.js b/karma.conf.js deleted file mode 100644 index e83c1eccca..0000000000 --- a/karma.conf.js +++ /dev/null @@ -1,8 +0,0 @@ -const env = process.env.NODE_ENV || 'base'; -const configFactory = require(`./.config/karma/${env}`); - -module.exports = function(config) { - config.set( - configFactory.create(config) - ); -}; diff --git a/karma.starter.ts b/karma.starter.ts deleted file mode 100644 index 3330b307e0..0000000000 --- a/karma.starter.ts +++ /dev/null @@ -1,17 +0,0 @@ -import './test/unit/_setupFiles/bootstrap'; - -//@ts-ignore -const specArg: string = __karma__.config.spec; - -// require all modules ending in ".spec.ts" from the -// './test' directory and all subdirectories -const testsContext = require.context('./test/unit', true, /.spec.ts$/); -let files = testsContext.keys(); - -if (specArg) { - const regEx = new RegExp(specArg); - - files = testsContext.keys().filter(key => key.match(regEx)); -} - -files.forEach(testsContext); diff --git a/package-lock.json b/package-lock.json index 2cf8736064..654ac62652 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,10 +27,6 @@ "@babel/preset-typescript": "^7.26.0", "@babel/register": "^7.25.9", "@babel/runtime": "^7.26.0", - "@types/exceljs": "^0.5.3", - "@types/jasmine": "^5.1.4", - "@types/jest": "^26.0.24", - "@types/jsdom": "^21.1.7", "@types/node": "^17.0.45", "@types/webpack-env": "^1.18.5", "@typescript-eslint/eslint-plugin": "^5.62.0", @@ -43,24 +39,10 @@ "env-cmd": "^10.1.0", "eslint": "^8.57.1", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-jasmine": "^4.2.2", - "eslint-plugin-jest": "^27.9.0", "eslint-plugin-jsdoc": "^50.5.0", "eslint-plugin-license-header": "^0.6.1", "eslint-plugin-prettier": "^5.2.1", "esm": "^3.2.25", - "exceljs": "^4.4.0", - "full-icu": "^1.5.0", - "jasmine": "^5.4.0", - "jest": "^26.6.3", - "jsdom": "^25.0.1", - "karma": "^6.4.4", - "karma-chrome-launcher": "^3.2.0", - "karma-firefox-launcher": "^2.1.3", - "karma-jasmine": "^5.1.0", - "karma-jasmine-html-reporter": "^2.1.0", - "karma-sourcemap-loader": "^0.4.0", - "karma-webpack": "^4.0.2", "license-checker": "^25.0.1", "markdown-it-footnote": "^4.0.0", "markdown-it-regex": "^0.2.0", @@ -71,7 +53,6 @@ "string-replace-loader": "^2.3.0", "tar": "^7.4.3", "terser-webpack-plugin": "^4.2.3", - "ts-jest": "^26.5.6", "ts-loader": "^8.4.0", "ts-node": "^10.9.2", "typedoc": "^0.19.2", @@ -84,31 +65,10 @@ "webpackbar": "^6.0.1" } }, - "node_modules/@asamuzakjp/css-color": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", - "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@csstools/css-calc": "^2.1.3", - "@csstools/css-color-parser": "^3.0.9", - "@csstools/css-parser-algorithms": "^3.0.4", - "@csstools/css-tokenizer": "^3.0.3", - "lru-cache": "^10.4.3" - } - }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/@babel/cli": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.28.3.tgz", - "integrity": "sha512-n1RU5vuCX0CsaqaXm9I0KUCNKNQMy5epmzl/xdSSm70bSqhg9GWhgeosypyQLc0bK24+Xpk1WGzZlI9pJtkZdg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.28.6.tgz", + "integrity": "sha512-6EUNcuBbNkj08Oj4gAZ+BUU8yLCgKzgVX4gaTh09Ya2C8ICM4P+G30g4m3akRxSYAp3A/gnWchrNst7px4/nUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -146,13 +106,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -161,9 +121,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", "dev": true, "license": "MIT", "engines": { @@ -171,21 +131,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -202,14 +162,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -232,13 +192,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -249,18 +209,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "engines": { @@ -289,17 +249,17 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", + "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" + "resolve": "^1.22.11" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -330,29 +290,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -375,9 +335,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -403,15 +363,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.28.5", "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -465,42 +425,42 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.28.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -577,14 +537,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -612,15 +572,15 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.28.0.tgz", - "integrity": "sha512-zOiZqvANjWDUaUS9xMxbMcK/Zccztbe/6ikvUXaG9nsPH3w6qh5UaPGAnirI/WhIbZ8m3OHU0ReyPrknG+ZKeg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.28.6.tgz", + "integrity": "sha512-RVdFPPyY9fCRAX68haPmOk2iyKW8PKJFthmm8NeSI3paNxKWGZIn99+VbIf0FrtCpFnPgnpF/L48tadi617ULg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-decorators": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-decorators": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -667,32 +627,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", @@ -706,30 +640,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.27.1.tgz", - "integrity": "sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.28.6.tgz", + "integrity": "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -752,13 +670,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -768,13 +686,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -783,40 +701,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -825,84 +717,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", @@ -919,30 +733,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -985,15 +783,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.6.tgz", + "integrity": "sha512-9knsChgsMzBV5Yh3kkhrZNxH3oCYAfMBkNNaVN4cP2RVlFPe8wYdwwcnOsAbkdDoV9UjFtOXWrWB52M8W4jNeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1003,14 +801,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { @@ -1037,13 +835,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1053,14 +851,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1070,14 +868,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1087,18 +885,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1108,14 +906,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1142,14 +940,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1175,14 +973,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.28.6.tgz", + "integrity": "sha512-5suVoXjC14lUN6ZL9OLKIHCNVWCrqGqlmEp/ixdXjvgnEl/kauLvvMO/Xw9NyMc95Joj1AeLVPVMvibBgSoFlA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1208,14 +1006,14 @@ } }, "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1225,13 +1023,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1292,13 +1090,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1324,13 +1122,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", - "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1373,14 +1171,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1459,13 +1257,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1475,13 +1273,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1491,17 +1289,17 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1528,13 +1326,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1544,13 +1342,13 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1577,14 +1375,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1594,15 +1392,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1644,17 +1442,17 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", - "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1697,13 +1495,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.6.tgz", + "integrity": "sha512-eZhoEZHYQLL5uc1gS5e9/oTknS0sSSAtd5TkKMUp3J+S/CaUjagc0kOUPsEbDmMeva0nC3WWl4SxVY6+OBuxfw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1713,14 +1511,14 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1783,13 +1581,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { @@ -1848,17 +1646,17 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.5.tgz", - "integrity": "sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-create-class-features-plugin": "^7.28.5", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1" + "@babel/plugin-syntax-typescript": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1884,14 +1682,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1918,14 +1716,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1935,76 +1733,76 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", - "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.6.tgz", + "integrity": "sha512-GaTI4nXDrs7l0qaJ6Rg06dtOXTBCG6TMDB44zbqofCIC4PqC7SEvmFFtpxzCDw9W5aJ7RKVshgXTLvLdBFV/qw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/compat-data": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.6", + "@babel/plugin-transform-async-to-generator": "^7.28.6", "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.5", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.28.6", "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.28.6", "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.28.5", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", "@babel/plugin-transform-export-namespace-from": "^7.27.1", "@babel/plugin-transform-for-of": "^7.27.1", "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", "@babel/plugin-transform-member-expression-literals": "^7.27.1", "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", "@babel/plugin-transform-modules-systemjs": "^7.28.5", "@babel/plugin-transform-modules-umd": "^7.27.1", "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.4", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.28.5", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.4", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.6", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", "@babel/plugin-transform-reserved-words": "^7.27.1", "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", "@babel/plugin-transform-sticky-regex": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-typeof-symbol": "^7.27.1", "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", @@ -2089,9 +1887,9 @@ } }, "node_modules/@babel/register": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.3.tgz", - "integrity": "sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.6.tgz", + "integrity": "sha512-pgcbbEl/dWQYb6L6Yew6F94rdwygfuv+vJ/tXfwIOYAfPB6TNWpXUMEtEq3YuTeHRdvMIhvz13bkT9CNaS+wqA==", "dev": true, "license": "MIT", "dependencies": { @@ -2109,9 +1907,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "dev": true, "license": "MIT", "engines": { @@ -2119,33 +1917,33 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", "debug": "^4.3.1" }, "engines": { @@ -2153,9 +1951,9 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { @@ -2166,46 +1964,12 @@ "node": ">=6.9.0" } }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" - }, - "engines": { - "node": ">=0.1.95" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -2224,121 +1988,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -2367,9 +2016,9 @@ } }, "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { - "version": "8.49.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.49.0.tgz", - "integrity": "sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", "dev": true, "license": "MIT", "engines": { @@ -2381,9 +2030,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2443,51 +2092,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@fast-csv/format": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", - "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.isboolean": "^3.0.3", - "lodash.isequal": "^4.5.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0" - } - }, - "node_modules/@fast-csv/format/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@fast-csv/parse": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz", - "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "^14.0.1", - "lodash.escaperegexp": "^4.1.2", - "lodash.groupby": "^4.6.0", - "lodash.isfunction": "^3.0.9", - "lodash.isnil": "^4.0.0", - "lodash.isundefined": "^3.0.1", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/@fast-csv/parse/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -2556,342 +2160,193 @@ "node": "20 || >=22" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, "license": "ISC", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "minipass": "^7.0.4" }, "engines": { - "node": ">=12" + "node": ">=18.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.0.0" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "node_modules/@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^7.0.4" + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" }, "engines": { - "node": ">=18.0.0" + "node": ">=4" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" + "engines": { + "node": ">= 8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" } }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" } }, - "node_modules/@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" }, "engines": { - "node": ">= 10.14.2" + "node": ">=10" } }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "bin": { + "mkdirp": "bin/cmd.js" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/core/node_modules/rimraf": { + "node_modules/@npmcli/move-file/node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", @@ -2908,1787 +2363,1758 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/core/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" } }, - "node_modules/@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" } }, - "node_modules/@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", - "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "defer-to-connect": "^1.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" } }, - "node_modules/@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" + "@types/connect": "*", + "@types/node": "*" } }, - "node_modules/@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, "license": "MIT", "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.4", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^4.0.3", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "node-notifier": "^8.0.0" + "@types/node": "*" } }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@types/express-serve-static-core": "*", + "@types/node": "*" } }, - "node_modules/@jest/reporters/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, "license": "MIT", "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.4", - "source-map": "^0.6.0" - }, - "engines": { - "node": ">= 10.14.2" + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" } }, - "node_modules/@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" } }, - "node_modules/@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" - }, - "engines": { - "node": ">= 10.14.2" + "@types/minimatch": "*", + "@types/node": "*" } }, - "node_modules/@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "node_modules/@types/highlight.js": { + "version": "9.12.4", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", + "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", - "babel-plugin-istanbul": "^6.0.0", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", - "pirates": "^4.0.1", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } + "license": "MIT" }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "@types/node": "*" } }, - "node_modules/@jest/transform/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, - "node_modules/@jest/transform/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "node_modules/@types/markdown-it": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-10.0.3.tgz", + "integrity": "sha512-daHJk22isOUvNssVGF2zDnnSyxHhFYhtjeX4oQaKD6QzL3ZR1QSgiD1g+Q6/WSWYVogNXYDXODtbgW/WiFCtyw==", "dev": true, "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "@types/highlight.js": "^9.7.0", + "@types/linkify-it": "*", + "@types/mdurl": "*", + "highlight.js": "^9.7.0" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@types/markdown-it/node_modules/highlight.js": { + "version": "9.18.5", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz", + "integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==", + "deprecated": "Support has ended for 9.x series. Upgrade to @latest", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "hasInstallScript": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "*" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } + "license": "MIT" }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } + "license": "MIT" }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } + "license": "MIT" }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/@types/q": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.8.tgz", + "integrity": "sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==", "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } + "license": "MIT" }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@types/node": "*" } }, - "node_modules/@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", "dev": true, "license": "MIT", "dependencies": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - }, - "engines": { - "node": ">=4" + "@types/http-errors": "*", + "@types/node": "*" } }, - "node_modules/@nicolo-ribaudo/chokidar-2": { - "version": "2.1.8-no-fsevents.3", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", - "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", + "node_modules/@types/source-list-map": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.6.tgz", + "integrity": "sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@types/tapable": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.12.tgz", + "integrity": "sha512-bTHG8fcxEqv1M9+TD14P8ok8hjxoOCkfKc8XXLaaD05kI7ohpeI956jtDOD3XHKBQrlyPughUtzm1jtVhHpA5Q==", "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } + "license": "MIT" }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@types/uglify-js": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.5.tgz", + "integrity": "sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "source-map": "^0.6.1" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@types/webpack": { + "version": "4.41.40", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.40.tgz", + "integrity": "sha512-u6kMFSBM9HcoTpUXnL6mt2HSzftqb3JgYV6oxIgL2dl6sX6aCa5k6SOkzv5DuZjBTPUE/dJltKtwwuqrkZHpfw==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } + "@types/node": "*", + "@types/tapable": "^1", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "anymatch": "^3.0.0", + "source-map": "^0.6.0" + } }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "node_modules/@types/webpack-dev-server": { + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@types/webpack-dev-server/-/webpack-dev-server-3.11.6.tgz", + "integrity": "sha512-XCph0RiiqFGetukCTC3KVnY1jwLcZ84illFRMbyFzCcWl90B/76ew0tSqF46oBhnLC4obNDG7dMO0JfTN0MgMQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" + "@types/connect-history-api-fallback": "*", + "@types/express": "*", + "@types/serve-static": "*", + "@types/webpack": "^4", + "http-proxy-middleware": "^1.0.0" } }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/@types/webpack-env": { + "version": "1.18.8", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", + "integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT" + }, + "node_modules/@types/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-4nZOdMwSPHZ4pTEZzSp0AsTM4K7Qmu40UKW4tJDiOVs20UzYF9l+qUe4s0ftfN0pin06n+5cWWDJXH+sbhAiDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + } + }, + "node_modules/@types/webpack-sources/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=10" + "node": ">= 12" } }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "license": "MIT", "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "license": "MIT", + "license": "ISC", "bin": { - "mkdirp": "bin/cmd.js" + "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, - "node_modules/@npmcli/move-file/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", "dependencies": { - "glob": "^7.1.3" + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, "engines": { - "node": ">=14" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://opencollective.com/pkgr" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, - "license": "BSD-3-Clause", + "license": "BSD-2-Clause", "dependencies": { - "type-detect": "4.0.8" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^1.7.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "license": "MIT", "dependencies": { - "defer-to-connect": "^1.0.1" + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" }, "engines": { - "node": ">=6" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "license": "MIT", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">= 6" + "node": ">=10" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", - "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "node_modules/@vue/babel-helper-vue-jsx-merge-props": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", + "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", "dev": true, "license": "MIT" }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", + "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", "dev": true, "license": "MIT" }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", + "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@vue/babel-helper-vue-transform-on": "1.5.0", + "@vue/babel-plugin-resolve-type": "1.5.0", + "@vue/shared": "^3.5.18" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } } }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", + "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.0.0" + "@babel/code-frame": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/parser": "^7.28.0", + "@vue/compiler-sfc": "^3.5.18" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "node_modules/@vue/babel-plugin-transform-vue-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", + "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/helper-module-imports": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "html-tags": "^2.0.0", + "lodash.kebabcase": "^4.1.1", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "node_modules/@vue/babel-preset-app": { + "version": "4.5.19", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.5.19.tgz", + "integrity": "sha512-VCNRiAt2P/bLo09rYt3DLe6xXUMlhJwrvU18Ddd/lYJgC7s8+wvhgYs+MTx4OiAXdu58drGwSBO9SPx7C6J82Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.2" + "@babel/core": "^7.11.0", + "@babel/helper-compilation-targets": "^7.9.6", + "@babel/helper-module-imports": "^7.8.3", + "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-proposal-decorators": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-jsx": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.11.0", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.0", + "@vue/babel-plugin-jsx": "^1.0.3", + "@vue/babel-preset-jsx": "^1.2.4", + "babel-plugin-dynamic-import-node": "^2.3.3", + "core-js": "^3.6.5", + "core-js-compat": "^3.6.5", + "semver": "^6.1.0" + }, + "peerDependencies": { + "@babel/core": "*", + "core-js": "^3", + "vue": "^2 || ^3.0.0-0" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + }, + "vue": { + "optional": true + } } }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "node_modules/@vue/babel-preset-jsx": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", + "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", "dev": true, "license": "MIT", "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", + "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", + "@vue/babel-sugar-functional-vue": "^1.4.0", + "@vue/babel-sugar-inject-h": "^1.4.0", + "@vue/babel-sugar-v-model": "^1.4.0", + "@vue/babel-sugar-v-on": "^1.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0", + "vue": "*" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "node_modules/@vue/babel-sugar-composition-api-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", + "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "node_modules/@vue/babel-sugar-composition-api-render-instance": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", + "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", "dev": true, "license": "MIT", "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "node_modules/@vue/babel-sugar-functional-vue": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", + "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/exceljs": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@types/exceljs/-/exceljs-0.5.3.tgz", - "integrity": "sha512-a0PLZEJGbA4kHHoSS8cQ20ynIv17vCBV1reqsrX5ksQQb077YYvhEKC82lEq6/+mMufhk68KJ5jwugL3DKG8sQ==", + "node_modules/@vue/babel-sugar-inject-h": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", + "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@babel/plugin-syntax-jsx": "^7.2.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/express": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "node_modules/@vue/babel-sugar-v-model": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", + "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "^2" + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0", + "html-tags": "^2.0.0", + "svg-tags": "^1.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/express-serve-static-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "node_modules/@vue/babel-sugar-v-on": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", + "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", "dev": true, "license": "MIT", "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" + "@babel/plugin-syntax-jsx": "^7.2.0", + "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", + "camelcase": "^5.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "node_modules/@vue/compiler-core": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz", + "integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@babel/parser": "^7.28.5", + "@vue/shared": "3.5.27", + "entities": "^7.0.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" } }, - "node_modules/@types/highlight.js": { - "version": "9.12.4", - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", - "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "node_modules/@vue/compiler-dom": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz", + "integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.27", + "@vue/shared": "3.5.27" + } }, - "node_modules/@types/http-proxy": { - "version": "1.17.17", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", - "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "node_modules/@vue/compiler-sfc": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz", + "integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@babel/parser": "^7.28.5", + "@vue/compiler-core": "3.5.27", + "@vue/compiler-dom": "3.5.27", + "@vue/compiler-ssr": "3.5.27", + "@vue/shared": "3.5.27", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "node_modules/@vue/compiler-ssr": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz", + "integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.27", + "@vue/shared": "3.5.27" + } }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "node_modules/@vue/component-compiler-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", + "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*" + "consolidate": "^0.15.1", + "hash-sum": "^1.0.2", + "lru-cache": "^4.1.2", + "merge-source-map": "^1.1.0", + "postcss": "^7.0.36", + "postcss-selector-parser": "^6.0.2", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" + }, + "optionalDependencies": { + "prettier": "^1.18.2 || ^2.0.0" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@types/istanbul-lib-report": "*" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, - "node_modules/@types/jasmine": { - "version": "5.1.13", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.13.tgz", - "integrity": "sha512-MYCcDkruFc92LeYZux5BC0dmqo2jk+M5UIZ4/oFnAPCXN9mCcQhLyj7F3/Za7rocVyt5YRr1MmqJqFlvQ9LVcg==", + "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/@types/jest": { - "version": "26.0.24", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", - "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", + "node_modules/@vue/component-compiler-utils/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/@types/jsdom": { - "version": "21.1.7", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", - "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", + "node_modules/@vue/component-compiler-utils/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "node_modules/@vue/component-compiler-utils/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/@types/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "node_modules/@vue/shared": { + "version": "3.5.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz", + "integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==", "dev": true, "license": "MIT" }, - "node_modules/@types/markdown-it": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-10.0.3.tgz", - "integrity": "sha512-daHJk22isOUvNssVGF2zDnnSyxHhFYhtjeX4oQaKD6QzL3ZR1QSgiD1g+Q6/WSWYVogNXYDXODtbgW/WiFCtyw==", + "node_modules/@vuepress/core": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.9.10.tgz", + "integrity": "sha512-H9ddo5fSinPb8QYl8OJFbZikMpOW84bm/U3Drzz8CnCXNtpda7CU2wX/XzOhe98G8jp45xhtZRkxOrqzBBAShA==", "dev": true, "license": "MIT", "dependencies": { - "@types/highlight.js": "^9.7.0", - "@types/linkify-it": "*", - "@types/mdurl": "*", - "highlight.js": "^9.7.0" + "@babel/core": "^7.8.4", + "@vue/babel-preset-app": "^4.1.2", + "@vuepress/markdown": "1.9.10", + "@vuepress/markdown-loader": "1.9.10", + "@vuepress/plugin-last-updated": "1.9.10", + "@vuepress/plugin-register-components": "1.9.10", + "@vuepress/shared-utils": "1.9.10", + "@vuepress/types": "1.9.10", + "autoprefixer": "^9.5.1", + "babel-loader": "^8.0.4", + "bundle-require": "2.1.8", + "cache-loader": "^3.0.0", + "chokidar": "^2.0.3", + "connect-history-api-fallback": "^1.5.0", + "copy-webpack-plugin": "^5.0.2", + "core-js": "^3.6.4", + "cross-spawn": "^6.0.5", + "css-loader": "^2.1.1", + "esbuild": "0.14.7", + "file-loader": "^3.0.1", + "js-yaml": "^3.13.1", + "lru-cache": "^5.1.1", + "mini-css-extract-plugin": "0.6.0", + "optimize-css-assets-webpack-plugin": "^5.0.1", + "portfinder": "^1.0.13", + "postcss-loader": "^3.0.0", + "postcss-safe-parser": "^4.0.1", + "toml": "^3.0.0", + "url-loader": "^1.0.1", + "vue": "^2.6.10", + "vue-loader": "^15.7.1", + "vue-router": "^3.4.5", + "vue-server-renderer": "^2.6.10", + "vue-template-compiler": "^2.6.10", + "vuepress-html-webpack-plugin": "^3.2.0", + "vuepress-plugin-container": "^2.0.2", + "webpack": "^4.8.1", + "webpack-chain": "^6.0.0", + "webpack-dev-server": "^3.5.1", + "webpack-merge": "^4.1.2", + "webpackbar": "3.2.0" + }, + "engines": { + "node": ">=8.6" } }, - "node_modules/@types/markdown-it/node_modules/highlight.js": { - "version": "9.18.5", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz", - "integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==", - "deprecated": "Support has ended for 9.x series. Upgrade to @latest", + "node_modules/@vuepress/core/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true, - "hasInstallScript": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/@types/mdurl": { + "node_modules/@vuepress/core/node_modules/anymatch": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "node_modules/@vuepress/core/node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "node_modules/@vuepress/core/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "node_modules/@vuepress/core/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@types/prettier": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", - "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/q": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.8.tgz", - "integrity": "sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==", + "node_modules/@vuepress/core/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "node_modules/@vuepress/core/node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "node_modules/@vuepress/core/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "node_modules/@vuepress/core/node_modules/consola": { + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", "dev": true, "license": "MIT" }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "node_modules/@vuepress/core/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" } }, - "node_modules/@types/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "node_modules/@vuepress/core/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/http-errors": "*", - "@types/node": "*" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/source-list-map": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.6.tgz", - "integrity": "sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==", + "node_modules/@vuepress/core/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true, "license": "MIT" }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "node_modules/@vuepress/core/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@types/tapable": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.12.tgz", - "integrity": "sha512-bTHG8fcxEqv1M9+TD14P8ok8hjxoOCkfKc8XXLaaD05kI7ohpeI956jtDOD3XHKBQrlyPughUtzm1jtVhHpA5Q==", + "node_modules/@vuepress/core/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", "dev": true, - "license": "MIT" + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "node_modules/@vuepress/core/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } }, - "node_modules/@types/uglify-js": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.5.tgz", - "integrity": "sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==", + "node_modules/@vuepress/core/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "license": "MIT", "dependencies": { - "source-map": "^0.6.1" + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/webpack": { - "version": "4.41.40", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.40.tgz", - "integrity": "sha512-u6kMFSBM9HcoTpUXnL6mt2HSzftqb3JgYV6oxIgL2dl6sX6aCa5k6SOkzv5DuZjBTPUE/dJltKtwwuqrkZHpfw==", + "node_modules/@vuepress/core/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "@types/tapable": "^1", - "@types/uglify-js": "*", - "@types/webpack-sources": "*", - "anymatch": "^3.0.0", - "source-map": "^0.6.0" + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/webpack-dev-server": { - "version": "3.11.6", - "resolved": "https://registry.npmjs.org/@types/webpack-dev-server/-/webpack-dev-server-3.11.6.tgz", - "integrity": "sha512-XCph0RiiqFGetukCTC3KVnY1jwLcZ84illFRMbyFzCcWl90B/76ew0tSqF46oBhnLC4obNDG7dMO0JfTN0MgMQ==", + "node_modules/@vuepress/core/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "license": "MIT", "dependencies": { - "@types/connect-history-api-fallback": "*", - "@types/express": "*", - "@types/serve-static": "*", - "@types/webpack": "^4", - "http-proxy-middleware": "^1.0.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/@types/webpack-env": { - "version": "1.18.8", - "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", - "integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-4nZOdMwSPHZ4pTEZzSp0AsTM4K7Qmu40UKW4tJDiOVs20UzYF9l+qUe4s0ftfN0pin06n+5cWWDJXH+sbhAiDw==", + "node_modules/@vuepress/core/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "@types/source-list-map": "*", - "source-map": "^0.7.3" + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/webpack-sources/node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "node_modules/@vuepress/core/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">= 12" + "node": ">=4" } }, - "node_modules/@types/yargs": { - "version": "15.0.20", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.20.tgz", - "integrity": "sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==", + "node_modules/@vuepress/core/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "kind-of": "^3.0.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=0.10.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/@vuepress/core/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "node_modules/@vuepress/core/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "node_modules/@vuepress/core/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=0.10.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "node_modules/@vuepress/core/node_modules/micromatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=0.10.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "node_modules/@vuepress/core/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=4" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "node_modules/@vuepress/core/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=0.10" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/@vuepress/core/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "semver": "bin/semver" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "node_modules/@vuepress/core/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "shebang-regex": "^1.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">=0.10.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/@vuepress/core/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "node_modules/@vuepress/core/node_modules/std-env": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-2.3.1.tgz", + "integrity": "sha512-eOsoKTWnr6C8aWrqJJ2KAReXoa7Vn5Ywyw6uCXgA/xDhxPoaIsBa5aNJmISY04dLwXPBnDHW4diGM7Sn5K4R/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "ci-info": "^3.1.1" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vue/babel-helper-vue-jsx-merge-props": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", - "integrity": "sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/babel-helper-vue-transform-on": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", - "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/babel-plugin-jsx": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", - "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", + "node_modules/@vuepress/core/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.2", - "@vue/babel-helper-vue-transform-on": "1.5.0", - "@vue/babel-plugin-resolve-type": "1.5.0", - "@vue/shared": "^3.5.18" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - } + "engines": { + "node": ">=6" } }, - "node_modules/@vue/babel-plugin-resolve-type": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", - "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "node_modules/@vuepress/core/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/parser": "^7.28.0", - "@vue/compiler-sfc": "^3.5.18" - }, - "funding": { - "url": "https://github.com/sponsors/sxzz" + "ansi-regex": "^4.1.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6" } }, - "node_modules/@vue/babel-plugin-transform-vue-jsx": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-plugin-transform-vue-jsx/-/babel-plugin-transform-vue-jsx-1.4.0.tgz", - "integrity": "sha512-Fmastxw4MMx0vlgLS4XBX0XiBbUFzoMGeVXuMV08wyOfXdikAFqBTuYPR0tlk+XskL19EzHc39SgjrPGY23JnA==", + "node_modules/@vuepress/core/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", - "html-tags": "^2.0.0", - "lodash.kebabcase": "^4.1.1", - "svg-tags": "^1.0.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@vue/babel-preset-app": { - "version": "4.5.19", - "resolved": "https://registry.npmjs.org/@vue/babel-preset-app/-/babel-preset-app-4.5.19.tgz", - "integrity": "sha512-VCNRiAt2P/bLo09rYt3DLe6xXUMlhJwrvU18Ddd/lYJgC7s8+wvhgYs+MTx4OiAXdu58drGwSBO9SPx7C6J82Q==", + "node_modules/@vuepress/core/node_modules/webpackbar": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-3.2.0.tgz", + "integrity": "sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.11.0", - "@babel/helper-compilation-targets": "^7.9.6", - "@babel/helper-module-imports": "^7.8.3", - "@babel/plugin-proposal-class-properties": "^7.8.3", - "@babel/plugin-proposal-decorators": "^7.8.3", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-jsx": "^7.8.3", - "@babel/plugin-transform-runtime": "^7.11.0", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.0", - "@vue/babel-plugin-jsx": "^1.0.3", - "@vue/babel-preset-jsx": "^1.2.4", - "babel-plugin-dynamic-import-node": "^2.3.3", - "core-js": "^3.6.5", - "core-js-compat": "^3.6.5", - "semver": "^6.1.0" + "ansi-escapes": "^4.1.0", + "chalk": "^2.4.1", + "consola": "^2.6.0", + "figures": "^3.0.0", + "pretty-time": "^1.1.0", + "std-env": "^2.2.1", + "text-table": "^0.2.0", + "wrap-ansi": "^5.1.0" }, - "peerDependencies": { - "@babel/core": "*", - "core-js": "^3", - "vue": "^2 || ^3.0.0-0" + "engines": { + "node": ">= 6.9.0" }, - "peerDependenciesMeta": { - "core-js": { - "optional": true - }, - "vue": { - "optional": true - } + "peerDependencies": { + "webpack": "^3.0.0 || ^4.0.0" } }, - "node_modules/@vue/babel-preset-jsx": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-preset-jsx/-/babel-preset-jsx-1.4.0.tgz", - "integrity": "sha512-QmfRpssBOPZWL5xw7fOuHNifCQcNQC1PrOo/4fu6xlhlKJJKSA3HqX92Nvgyx8fqHZTUGMPHmFA+IDqwXlqkSA==", + "node_modules/@vuepress/core/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", - "@vue/babel-sugar-composition-api-inject-h": "^1.4.0", - "@vue/babel-sugar-composition-api-render-instance": "^1.4.0", - "@vue/babel-sugar-functional-vue": "^1.4.0", - "@vue/babel-sugar-inject-h": "^1.4.0", - "@vue/babel-sugar-v-model": "^1.4.0", - "@vue/babel-sugar-v-on": "^1.4.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0", - "vue": "*" + "isexe": "^2.0.0" }, - "peerDependenciesMeta": { - "vue": { - "optional": true - } + "bin": { + "which": "bin/which" } }, - "node_modules/@vue/babel-sugar-composition-api-inject-h": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-inject-h/-/babel-sugar-composition-api-inject-h-1.4.0.tgz", - "integrity": "sha512-VQq6zEddJHctnG4w3TfmlVp5FzDavUSut/DwR0xVoe/mJKXyMcsIibL42wPntozITEoY90aBV0/1d2KjxHU52g==", + "node_modules/@vuepress/core/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-syntax-jsx": "^7.2.0" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6" } }, - "node_modules/@vue/babel-sugar-composition-api-render-instance": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-composition-api-render-instance/-/babel-sugar-composition-api-render-instance-1.4.0.tgz", - "integrity": "sha512-6ZDAzcxvy7VcnCjNdHJ59mwK02ZFuP5CnucloidqlZwVQv5CQLijc3lGpR7MD3TWFi78J7+a8J56YxbCtHgT9Q==", + "node_modules/@vuepress/markdown": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.9.10.tgz", + "integrity": "sha512-sXTLjeZzH8SQuAL5AEH0hhsMljjNJbzWbBvzaj5yQCCdf+3sp/dJ0kwnBSnQjFPPnzPg5t3tLKGUYHyW0KiKzA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-syntax-jsx": "^7.2.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@vuepress/shared-utils": "1.9.10", + "markdown-it": "^8.4.1", + "markdown-it-anchor": "^5.0.2", + "markdown-it-chain": "^1.3.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-table-of-contents": "^0.4.0", + "prismjs": "^1.13.0" } }, - "node_modules/@vue/babel-sugar-functional-vue": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-functional-vue/-/babel-sugar-functional-vue-1.4.0.tgz", - "integrity": "sha512-lTEB4WUFNzYt2In6JsoF9sAYVTo84wC4e+PoZWSgM6FUtqRJz7wMylaEhSRgG71YF+wfLD6cc9nqVeXN2rwBvw==", + "node_modules/@vuepress/markdown-loader": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.9.10.tgz", + "integrity": "sha512-94BlwKc+lOaN/A5DkyA9KWHvMlMC1sWunAXE3Tv0WYzgYLDs9QqCsx7L5kLkpcOOVVm/8kBJumnXvVBwhqJddw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-syntax-jsx": "^7.2.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@vuepress/markdown": "1.9.10", + "loader-utils": "^1.1.0", + "lru-cache": "^5.1.1" } }, - "node_modules/@vue/babel-sugar-inject-h": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-inject-h/-/babel-sugar-inject-h-1.4.0.tgz", - "integrity": "sha512-muwWrPKli77uO2fFM7eA3G1lAGnERuSz2NgAxuOLzrsTlQl8W4G+wwbM4nB6iewlKbwKRae3nL03UaF5ffAPMA==", + "node_modules/@vuepress/markdown-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-syntax-jsx": "^7.2.0" + "minimist": "^1.2.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/@vue/babel-sugar-v-model": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-model/-/babel-sugar-v-model-1.4.0.tgz", - "integrity": "sha512-0t4HGgXb7WHYLBciZzN5s0Hzqan4Ue+p/3FdQdcaHAb7s5D9WZFGoSxEZHrR1TFVZlAPu1bejTKGeAzaaG3NCQ==", + "node_modules/@vuepress/markdown-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", - "camelcase": "^5.0.0", - "html-tags": "^2.0.0", - "svg-tags": "^1.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=4.0.0" } }, - "node_modules/@vue/babel-sugar-v-on": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@vue/babel-sugar-v-on/-/babel-sugar-v-on-1.4.0.tgz", - "integrity": "sha512-m+zud4wKLzSKgQrWwhqRObWzmTuyzl6vOP7024lrpeJM4x2UhQtRDLgYjXAw9xBXjCwS0pP9kXjg91F9ZNo9JA==", + "node_modules/@vuepress/plugin-active-header-links": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.9.10.tgz", + "integrity": "sha512-2dRr3DE2UBFXhyMtLR3sGTdRyDM8YStuY6AOoQmoSgwy1IHt7PO7ypOuf1akF+1Nv8Q2aISU06q6TExZouu3Mw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-syntax-jsx": "^7.2.0", - "@vue/babel-plugin-transform-vue-jsx": "^1.4.0", - "camelcase": "^5.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@vuepress/types": "1.9.10", + "lodash.debounce": "^4.0.8" } }, - "node_modules/@vue/compiler-core": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", - "integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==", + "node_modules/@vuepress/plugin-last-updated": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.9.10.tgz", + "integrity": "sha512-YxzWGF/OfU6WsHSynZFn74NGGp7dY27Bjy9JyyFo8wF5+2V1gpyDjveHKHGKugS/pMXlxfjzhv9E2Wmy9R7Iog==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.25", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" + "@vuepress/types": "1.9.10", + "cross-spawn": "^6.0.5" } }, - "node_modules/@vue/compiler-core/node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "node_modules/@vuepress/plugin-last-updated/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "engines": { + "node": ">=4.8" } }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.25.tgz", - "integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==", + "node_modules/@vuepress/plugin-last-updated/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.25", - "@vue/shared": "3.5.25" + "engines": { + "node": ">=4" } }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.25.tgz", - "integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==", + "node_modules/@vuepress/plugin-last-updated/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/compiler-core": "3.5.25", - "@vue/compiler-dom": "3.5.25", - "@vue/compiler-ssr": "3.5.25", - "@vue/shared": "3.5.25", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.6", - "source-map-js": "^1.2.1" + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.25.tgz", - "integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==", + "node_modules/@vuepress/plugin-last-updated/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.25", - "@vue/shared": "3.5.25" + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@vue/component-compiler-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", - "integrity": "sha512-97sfH2mYNU+2PzGrmK2haqffDpVASuib9/w2/noxiFi31Z54hW+q3izKQXXQZSNhtiUpAI36uSuYepeBe4wpHQ==", + "node_modules/@vuepress/plugin-last-updated/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, "license": "MIT", - "dependencies": { - "consolidate": "^0.15.1", - "hash-sum": "^1.0.2", - "lru-cache": "^4.1.2", - "merge-source-map": "^1.1.0", - "postcss": "^7.0.36", - "postcss-selector-parser": "^6.0.2", - "source-map": "~0.6.1", - "vue-template-es2015-compiler": "^1.9.0" - }, - "optionalDependencies": { - "prettier": "^1.18.2 || ^2.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@vue/component-compiler-utils/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "node_modules/@vuepress/plugin-last-updated/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "license": "ISC", "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "node_modules/@vue/component-compiler-utils/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vue/component-compiler-utils/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/@vuepress/plugin-nprogress": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.9.10.tgz", + "integrity": "sha512-I1kkm6yWUQd7vwiV3lEDVpVP0Lr04K0zlczU502lDUa1RufSZ7vt+mlF5fOM28GqT+pKTEToWmm+VNT/R3qvMQ==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "@vuepress/types": "1.9.10", + "nprogress": "^0.2.0" } }, - "node_modules/@vue/component-compiler-utils/node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "node_modules/@vuepress/plugin-register-components": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.9.10.tgz", + "integrity": "sha512-sgdJ5OydTPZAoTkselpvVP3Xsd6bfZ0FpaxOTinal0gJ99h49lvLu9bvzMx13rdGRFO/kRXn0qQQpwKTAfTPqA==", "dev": true, "license": "MIT", - "optional": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "dependencies": { + "@vuepress/shared-utils": "1.9.10", + "@vuepress/types": "1.9.10" } }, - "node_modules/@vue/component-compiler-utils/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vue/shared": { - "version": "3.5.25", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.25.tgz", - "integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==", + "node_modules/@vuepress/plugin-search": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.9.10.tgz", + "integrity": "sha512-bn2XJikaRgQZXvu8upCjOWrxbLHIRTqnJ3w7G0mo6jCYWGVsHNo6XhVpqylpLR2PWnHT/ImO2bGo38/5Bag/tQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@vuepress/types": "1.9.10" + } }, - "node_modules/@vuepress/core": { + "node_modules/@vuepress/shared-utils": { "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/core/-/core-1.9.10.tgz", - "integrity": "sha512-H9ddo5fSinPb8QYl8OJFbZikMpOW84bm/U3Drzz8CnCXNtpda7CU2wX/XzOhe98G8jp45xhtZRkxOrqzBBAShA==", + "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.9.10.tgz", + "integrity": "sha512-M9A3DocPih+V8dKK2Zg9FJQ/f3JZrYsdaM/vQ9F48l8bPlzxw5NvqXIYMK4kKcGEyerQNTWCudoCpLL5uiU0hg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.8.4", - "@vue/babel-preset-app": "^4.1.2", - "@vuepress/markdown": "1.9.10", - "@vuepress/markdown-loader": "1.9.10", - "@vuepress/plugin-last-updated": "1.9.10", - "@vuepress/plugin-register-components": "1.9.10", - "@vuepress/shared-utils": "1.9.10", - "@vuepress/types": "1.9.10", - "autoprefixer": "^9.5.1", - "babel-loader": "^8.0.4", - "bundle-require": "2.1.8", - "cache-loader": "^3.0.0", - "chokidar": "^2.0.3", - "connect-history-api-fallback": "^1.5.0", - "copy-webpack-plugin": "^5.0.2", - "core-js": "^3.6.4", - "cross-spawn": "^6.0.5", - "css-loader": "^2.1.1", - "esbuild": "0.14.7", - "file-loader": "^3.0.1", - "js-yaml": "^3.13.1", - "lru-cache": "^5.1.1", - "mini-css-extract-plugin": "0.6.0", - "optimize-css-assets-webpack-plugin": "^5.0.1", - "portfinder": "^1.0.13", - "postcss-loader": "^3.0.0", - "postcss-safe-parser": "^4.0.1", + "chalk": "^2.3.2", + "escape-html": "^1.0.3", + "fs-extra": "^7.0.1", + "globby": "^9.2.0", + "gray-matter": "^4.0.1", + "hash-sum": "^1.0.2", + "semver": "^6.0.0", "toml": "^3.0.0", - "url-loader": "^1.0.1", - "vue": "^2.6.10", - "vue-loader": "^15.7.1", - "vue-router": "^3.4.5", - "vue-server-renderer": "^2.6.10", - "vue-template-compiler": "^2.6.10", - "vuepress-html-webpack-plugin": "^3.2.0", - "vuepress-plugin-container": "^2.0.2", - "webpack": "^4.8.1", - "webpack-chain": "^6.0.0", - "webpack-dev-server": "^3.5.1", - "webpack-merge": "^4.1.2", - "webpackbar": "3.2.0" - }, - "engines": { - "node": ">=8.6" + "upath": "^1.1.0" } }, - "node_modules/@vuepress/core/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "node_modules/@vuepress/shared-utils/node_modules/@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 6" } }, - "node_modules/@vuepress/core/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/@vuepress/shared-utils/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "array-uniq": "^1.0.1" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "license": "ISC", - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/@vuepress/core/node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vuepress/core/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@vuepress/core/node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vuepress/core/node_modules/braces": { + "node_modules/@vuepress/shared-utils/node_modules/braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", @@ -4710,108 +4136,52 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "node_modules/@vuepress/shared-utils/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/@vuepress/core/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/@vuepress/core/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" + "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vuepress/core/node_modules/consola": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", - "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vuepress/core/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "node_modules/@vuepress/shared-utils/node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "dev": true, "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-type": "^3.0.0" }, "engines": { - "node": ">=4.8" + "node": ">=4" } }, - "node_modules/@vuepress/core/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/@vuepress/shared-utils/node_modules/fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" }, "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0" } }, - "node_modules/@vuepress/core/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vuepress/core/node_modules/fill-range": { + "node_modules/@vuepress/shared-utils/node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", @@ -4827,27 +4197,22 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", + "node_modules/@vuepress/shared-utils/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">= 4.0" + "node": ">=6 <7 || >=8" } }, - "node_modules/@vuepress/core/node_modules/glob-parent": { + "node_modules/@vuepress/shared-utils/node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", @@ -4858,7 +4223,7 @@ "path-dirname": "^1.0.0" } }, - "node_modules/@vuepress/core/node_modules/glob-parent/node_modules/is-glob": { + "node_modules/@vuepress/shared-utils/node_modules/glob-parent/node_modules/is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", @@ -4871,20 +4236,37 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "node_modules/@vuepress/shared-utils/node_modules/globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", "dev": true, "license": "MIT", "dependencies": { - "binary-extensions": "^1.0.0" + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/@vuepress/core/node_modules/is-descriptor": { + "node_modules/@vuepress/shared-utils/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@vuepress/shared-utils/node_modules/is-descriptor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", @@ -4898,7 +4280,7 @@ "node": ">= 0.4" } }, - "node_modules/@vuepress/core/node_modules/is-extendable": { + "node_modules/@vuepress/shared-utils/node_modules/is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", @@ -4911,17 +4293,7 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@vuepress/core/node_modules/is-number": { + "node_modules/@vuepress/shared-utils/node_modules/is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", @@ -4934,7 +4306,7 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/is-number/node_modules/kind-of": { + "node_modules/@vuepress/shared-utils/node_modules/is-number/node_modules/kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", @@ -4947,28 +4319,17 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vuepress/core/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "node_modules/@vuepress/shared-utils/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/@vuepress/core/node_modules/micromatch": { + "node_modules/@vuepress/shared-utils/node_modules/micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", @@ -4993,7 +4354,7 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/micromatch/node_modules/extend-shallow": { + "node_modules/@vuepress/shared-utils/node_modules/micromatch/node_modules/extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", @@ -5007,1241 +4368,1113 @@ "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "node_modules/@vuepress/shared-utils/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, "engines": { "node": ">=4" } }, - "node_modules/@vuepress/core/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/@vuepress/core/node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "node_modules/@vuepress/shared-utils/node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, "engines": { - "node": ">=0.10" - } - }, - "node_modules/@vuepress/core/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vuepress/core/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "node": ">=4" } }, - "node_modules/@vuepress/core/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/@vuepress/shared-utils/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^1.0.0" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/@vuepress/core/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/@vuepress/shared-utils/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 4.0.0" } }, - "node_modules/@vuepress/core/node_modules/std-env": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-2.3.1.tgz", - "integrity": "sha512-eOsoKTWnr6C8aWrqJJ2KAReXoa7Vn5Ywyw6uCXgA/xDhxPoaIsBa5aNJmISY04dLwXPBnDHW4diGM7Sn5K4R/g==", + "node_modules/@vuepress/theme-default": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.9.10.tgz", + "integrity": "sha512-XnXn9t+pYCIhWi3cZXJlighuy93FFm5yXdISAAlFlcNkshuGtqamkjacHV8q/QZMfOhSIs6wX7Hj88u2IsT5mw==", "dev": true, "license": "MIT", "dependencies": { - "ci-info": "^3.1.1" + "@vuepress/plugin-active-header-links": "1.9.10", + "@vuepress/plugin-nprogress": "1.9.10", + "@vuepress/plugin-search": "1.9.10", + "@vuepress/types": "1.9.10", + "docsearch.js": "^2.5.2", + "lodash": "^4.17.15", + "stylus": "^0.54.8", + "stylus-loader": "^3.0.2", + "vuepress-plugin-container": "^2.0.2", + "vuepress-plugin-smooth-scroll": "^0.0.3" } }, - "node_modules/@vuepress/core/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/@vuepress/types": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@vuepress/types/-/types-1.9.10.tgz", + "integrity": "sha512-TDNQn4og85onmBpLTTXXmncW3rUnYGr2MkuI8OIFJZetDNM49t1WbjNVlrT+kx7C6qXi6okDQgrHGYXajHZWfg==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "@types/markdown-it": "^10.0.0", + "@types/webpack-dev-server": "^3", + "webpack-chain": "^6.0.0" } }, - "node_modules/@vuepress/core/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" } }, - "node_modules/@vuepress/core/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } + "license": "MIT" }, - "node_modules/@vuepress/core/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" + "@webassemblyjs/wast-printer": "1.9.0" } }, - "node_modules/@vuepress/core/node_modules/webpackbar": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-3.2.0.tgz", - "integrity": "sha512-PC4o+1c8gWWileUfwabe0gqptlXUDJd5E0zbpr2xHP1VSOVlZVPBZ8j6NCR8zM5zbKdxPhctHXahgpNK1qFDPw==", + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true, + "license": "ISC" + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-escapes": "^4.1.0", - "chalk": "^2.4.1", - "consola": "^2.6.0", - "figures": "^3.0.0", - "pretty-time": "^1.1.0", - "std-env": "^2.2.1", - "text-table": "^0.2.0", - "wrap-ansi": "^5.1.0" - }, - "engines": { - "node": ">= 6.9.0" - }, - "peerDependencies": { - "webpack": "^3.0.0 || ^4.0.0" + "@webassemblyjs/ast": "1.9.0" } }, - "node_modules/@vuepress/core/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } + "license": "MIT" }, - "node_modules/@vuepress/core/node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" } }, - "node_modules/@vuepress/markdown": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/markdown/-/markdown-1.9.10.tgz", - "integrity": "sha512-sXTLjeZzH8SQuAL5AEH0hhsMljjNJbzWbBvzaj5yQCCdf+3sp/dJ0kwnBSnQjFPPnzPg5t3tLKGUYHyW0KiKzA==", + "node_modules/@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", "dev": true, "license": "MIT", "dependencies": { - "@vuepress/shared-utils": "1.9.10", - "markdown-it": "^8.4.1", - "markdown-it-anchor": "^5.0.2", - "markdown-it-chain": "^1.3.0", - "markdown-it-emoji": "^1.4.0", - "markdown-it-table-of-contents": "^0.4.0", - "prismjs": "^1.13.0" + "@xtuc/ieee754": "^1.2.0" } }, - "node_modules/@vuepress/markdown-loader": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/markdown-loader/-/markdown-loader-1.9.10.tgz", - "integrity": "sha512-94BlwKc+lOaN/A5DkyA9KWHvMlMC1sWunAXE3Tv0WYzgYLDs9QqCsx7L5kLkpcOOVVm/8kBJumnXvVBwhqJddw==", + "node_modules/@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", "dev": true, "license": "MIT", "dependencies": { - "@vuepress/markdown": "1.9.10", - "loader-utils": "^1.1.0", - "lru-cache": "^5.1.1" + "@xtuc/long": "4.2.2" } }, - "node_modules/@vuepress/markdown-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" } }, - "node_modules/@vuepress/markdown-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" } }, - "node_modules/@vuepress/plugin-active-header-links": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-active-header-links/-/plugin-active-header-links-1.9.10.tgz", - "integrity": "sha512-2dRr3DE2UBFXhyMtLR3sGTdRyDM8YStuY6AOoQmoSgwy1IHt7PO7ypOuf1akF+1Nv8Q2aISU06q6TExZouu3Mw==", + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", "dev": true, "license": "MIT", "dependencies": { - "@vuepress/types": "1.9.10", - "lodash.debounce": "^4.0.8" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" } }, - "node_modules/@vuepress/plugin-last-updated": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.9.10.tgz", - "integrity": "sha512-YxzWGF/OfU6WsHSynZFn74NGGp7dY27Bjy9JyyFo8wF5+2V1gpyDjveHKHGKugS/pMXlxfjzhv9E2Wmy9R7Iog==", + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", "dev": true, "license": "MIT", "dependencies": { - "@vuepress/types": "1.9.10", - "cross-spawn": "^6.0.5" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" } }, - "node_modules/@vuepress/plugin-last-updated/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", "dev": true, "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" } }, - "node_modules/@vuepress/plugin-last-updated/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" } }, - "node_modules/@vuepress/plugin-last-updated/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "license": "MIT", + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" } }, - "node_modules/@vuepress/plugin-last-updated/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^1.0.0" + "envinfo": "^7.7.3" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "webpack-cli": "4.x.x" } }, - "node_modules/@vuepress/plugin-last-updated/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@vuepress/plugin-last-updated/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" + "peerDependencies": { + "webpack-cli": "4.x.x" }, - "bin": { - "which": "bin/which" + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } } }, - "node_modules/@vuepress/plugin-nprogress": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-nprogress/-/plugin-nprogress-1.9.10.tgz", - "integrity": "sha512-I1kkm6yWUQd7vwiV3lEDVpVP0Lr04K0zlczU502lDUa1RufSZ7vt+mlF5fOM28GqT+pKTEToWmm+VNT/R3qvMQ==", + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", "dev": true, - "license": "MIT", - "dependencies": { - "@vuepress/types": "1.9.10", - "nprogress": "^0.2.0" - } + "license": "BSD-3-Clause" }, - "node_modules/@vuepress/plugin-register-components": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-register-components/-/plugin-register-components-1.9.10.tgz", - "integrity": "sha512-sgdJ5OydTPZAoTkselpvVP3Xsd6bfZ0FpaxOTinal0gJ99h49lvLu9bvzMx13rdGRFO/kRXn0qQQpwKTAfTPqA==", + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@vuepress/shared-utils": "1.9.10", - "@vuepress/types": "1.9.10" - } + "license": "Apache-2.0" }, - "node_modules/@vuepress/plugin-search": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/plugin-search/-/plugin-search-1.9.10.tgz", - "integrity": "sha512-bn2XJikaRgQZXvu8upCjOWrxbLHIRTqnJ3w7G0mo6jCYWGVsHNo6XhVpqylpLR2PWnHT/ImO2bGo38/5Bag/tQ==", + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, - "license": "MIT", - "dependencies": { - "@vuepress/types": "1.9.10" - } + "license": "ISC" }, - "node_modules/@vuepress/shared-utils": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/shared-utils/-/shared-utils-1.9.10.tgz", - "integrity": "sha512-M9A3DocPih+V8dKK2Zg9FJQ/f3JZrYsdaM/vQ9F48l8bPlzxw5NvqXIYMK4kKcGEyerQNTWCudoCpLL5uiU0hg==", + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^2.3.2", - "escape-html": "^1.0.3", - "fs-extra": "^7.0.1", - "globby": "^9.2.0", - "gray-matter": "^4.0.1", - "hash-sum": "^1.0.2", - "semver": "^6.0.0", - "toml": "^3.0.0", - "upath": "^1.1.0" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/@vuepress/shared-utils/node_modules/@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 6" + "node": ">= 0.6" } }, - "node_modules/@vuepress/shared-utils/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "dependencies": { - "array-uniq": "^1.0.1" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/@vuepress/shared-utils/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@vuepress/shared-utils/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "acorn": "^8.11.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/@vuepress/shared-utils/node_modules/dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "node_modules/agentkeepalive": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", + "integrity": "sha512-TnB6ziK363p7lR8QpeLC8aMr8EGYBKZTpgzQLfqTs3bR0Oo5VbKdwKf8h0dSzsYrB7lSCgfJnMZKqShvlq5Oyg==", "dev": true, "license": "MIT", - "dependencies": { - "path-type": "^3.0.0" - }, "engines": { - "node": ">=4" + "node": ">= 0.10.0" } }, - "node_modules/@vuepress/shared-utils/node_modules/fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, "license": "MIT", "dependencies": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=8" } }, - "node_modules/@vuepress/shared-utils/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@vuepress/shared-utils/node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", "dev": true, "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" + "peerDependencies": { + "ajv": ">=5.0.0" } }, - "node_modules/@vuepress/shared-utils/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" } }, - "node_modules/@vuepress/shared-utils/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "node_modules/algoliasearch": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.35.1.tgz", + "integrity": "sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.0" + "agentkeepalive": "^2.2.0", + "debug": "^2.6.9", + "envify": "^4.0.0", + "es6-promise": "^4.1.0", + "events": "^1.1.0", + "foreach": "^2.0.5", + "global": "^4.3.2", + "inherits": "^2.0.1", + "isarray": "^2.0.1", + "load-script": "^1.0.0", + "object-keys": "^1.0.11", + "querystring-es3": "^0.2.1", + "reduce": "^1.0.1", + "semver": "^5.1.0", + "tunnel-agent": "^0.6.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.8" } }, - "node_modules/@vuepress/shared-utils/node_modules/globby": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "node_modules/algoliasearch/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^1.0.2", - "dir-glob": "^2.2.2", - "fast-glob": "^2.2.6", - "glob": "^7.1.3", - "ignore": "^4.0.3", - "pify": "^4.0.1", - "slash": "^2.0.0" - }, - "engines": { - "node": ">=6" + "ms": "2.0.0" } }, - "node_modules/@vuepress/shared-utils/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "node_modules/algoliasearch/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" + "license": "MIT" + }, + "node_modules/algoliasearch/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "node_modules/@vuepress/shared-utils/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "string-width": "^4.1.0" } }, - "node_modules/@vuepress/shared-utils/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", "dev": true, "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/@vuepress/shared-utils/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" + "type-fest": "^0.21.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@vuepress/shared-utils/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@vuepress/shared-utils/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/@vuepress/shared-utils/node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "license": "MIT", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/@vuepress/shared-utils/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "pify": "^3.0.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=4" + "node": ">= 8" } }, - "node_modules/@vuepress/shared-utils/node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true, + "license": "ISC" + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=14" } }, - "node_modules/@vuepress/shared-utils/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", "dev": true, "license": "MIT", - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/@vuepress/theme-default": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/theme-default/-/theme-default-1.9.10.tgz", - "integrity": "sha512-XnXn9t+pYCIhWi3cZXJlighuy93FFm5yXdISAAlFlcNkshuGtqamkjacHV8q/QZMfOhSIs6wX7Hj88u2IsT5mw==", + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true, "license": "MIT", - "dependencies": { - "@vuepress/plugin-active-header-links": "1.9.10", - "@vuepress/plugin-nprogress": "1.9.10", - "@vuepress/plugin-search": "1.9.10", - "@vuepress/types": "1.9.10", - "docsearch.js": "^2.5.2", - "lodash": "^4.17.15", - "stylus": "^0.54.8", - "stylus-loader": "^3.0.2", - "vuepress-plugin-container": "^2.0.2", - "vuepress-plugin-smooth-scroll": "^0.0.3" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@vuepress/types": { - "version": "1.9.10", - "resolved": "https://registry.npmjs.org/@vuepress/types/-/types-1.9.10.tgz", - "integrity": "sha512-TDNQn4og85onmBpLTTXXmncW3rUnYGr2MkuI8OIFJZetDNM49t1WbjNVlrT+kx7C6qXi6okDQgrHGYXajHZWfg==", + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", "dev": true, "license": "MIT", - "dependencies": { - "@types/markdown-it": "^10.0.0", - "@types/webpack-dev-server": "^3", - "webpack-chain": "^6.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", - "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", - "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", - "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", - "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-code-frame": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", - "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/wast-printer": "1.9.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", - "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/@webassemblyjs/helper-module-context": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", - "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.9.0" + "engines": { + "node": ">=8" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", - "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", - "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", - "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", "dev": true, "license": "MIT", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", - "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "node_modules/array.prototype.reduce": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.8.tgz", + "integrity": "sha512-DwuEqgXFBwbmZSRqt3BpQigWNUoqw9Ml2dTWdF3B2zQlQX4OeUE0zyuzX0fX0IbTvjdkZbcBTU3idgpO78qkTw==", "dev": true, "license": "MIT", "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", - "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", - "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/helper-wasm-section": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-opt": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "@webassemblyjs/wast-printer": "1.9.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-array-method-boxes-properly": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "is-string": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", - "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", - "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" + "printable-characters": "^1.0.42" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", - "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" - } + "license": "MIT" }, - "node_modules/@webassemblyjs/wast-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", - "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/floating-point-hex-parser": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-code-frame": "1.9.0", - "@webassemblyjs/helper-fsm": "1.9.0", - "@xtuc/long": "4.2.2" + "safer-buffer": "~2.1.0" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", - "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", - "@xtuc/long": "4.2.2" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "node_modules/@webpack-cli/configtest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", - "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "MIT", - "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" - } + "license": "MIT" }, - "node_modules/@webpack-cli/info": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", - "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "node_modules/assert": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", + "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", "dev": true, "license": "MIT", "dependencies": { - "envinfo": "^7.7.3" - }, - "peerDependencies": { - "webpack-cli": "4.x.x" + "object.assign": "^4.1.4", + "util": "^0.10.4" } }, - "node_modules/@webpack-cli/serve": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", - "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "license": "MIT", - "peerDependencies": { - "webpack-cli": "4.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } + "engines": { + "node": ">=0.8" } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "node_modules/assert/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true, "license": "ISC" }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/assert/node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" + "inherits": "2.0.3" } }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } + "license": "MIT" }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" }, - "node_modules/acorn-globals/node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">= 0.4" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } + "license": "MIT" }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } + "license": "MIT" }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">= 14" + "node": ">= 4.0.0" } }, - "node_modules/agentkeepalive": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", - "integrity": "sha512-TnB6ziK363p7lR8QpeLC8aMr8EGYBKZTpgzQLfqTs3bR0Oo5VbKdwKf8h0dSzsYrB7lSCgfJnMZKqShvlq5Oyg==", + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true, - "license": "MIT", + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, "engines": { - "node": ">= 0.10.0" + "node": ">= 4.5.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/autocomplete.js": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.36.0.tgz", + "integrity": "sha512-jEwUXnVMeCHHutUt10i/8ZiRaCb0Wo+ZyKxeGsYwBDtw6EJHqEeDrq4UwZRD8YBSvp3g6klP678il2eeiVXN2Q==", "dev": true, "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" + "immediate": "^3.2.3" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/autoprefixer": { + "version": "9.8.8", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", + "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "picocolors": "^0.2.1", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" } }, - "node_modules/ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "node_modules/autoprefixer/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": ">=5.0.0" - } + "license": "ISC" }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "node_modules/autoprefixer/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/algoliasearch": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-3.35.1.tgz", - "integrity": "sha512-K4yKVhaHkXfJ/xcUnil04xiSrB8B8yHZoFEhWNpXg23eiCnqvTZw1tn/SqvdsANlYHLJlKl0qi3I/Q2Sqo7LwQ==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "license": "MIT", "dependencies": { - "agentkeepalive": "^2.2.0", - "debug": "^2.6.9", - "envify": "^4.0.0", - "es6-promise": "^4.1.0", - "events": "^1.1.0", - "foreach": "^2.0.5", - "global": "^4.3.2", - "inherits": "^2.0.1", - "isarray": "^2.0.1", - "load-script": "^1.0.0", - "object-keys": "^1.0.11", - "querystring-es3": "^0.2.1", - "reduce": "^1.0.1", - "semver": "^5.1.0", - "tunnel-agent": "^0.6.0" + "possible-typed-array-names": "^1.0.0" }, "engines": { - "node": ">=0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/algoliasearch/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "license": "Apache-2.0", + "engines": { + "node": "*" } }, - "node_modules/algoliasearch/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", "dev": true, "license": "MIT" }, - "node_modules/algoliasearch/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/babel-loader": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", + "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "license": "MIT", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.4", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" } }, - "node_modules/alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==", + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "node_modules/babel-loader/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^4.1.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "node_modules/babel-loader/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/babel-loader/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "semver": "^6.0.0" }, "engines": { "node": ">=8" @@ -6250,3027 +5483,3028 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/babel-loader/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "license": "Apache-2.0", - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/babel-loader/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, "engines": { "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/babel-loader/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "find-up": "^4.0.0" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" + "object.assign": "^4.1.0" } }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", + "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.6", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, "license": "MIT", "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" }, - "engines": { - "node": ">= 10" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", + "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", "dev": true, "license": "MIT", "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" + "@babel/helper-define-polyfill-provider": "^0.6.6" }, - "engines": { - "node": ">= 6" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/archiver-utils/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/babel-plugin-transform-inline-environment-variables": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-environment-variables/-/babel-plugin-transform-inline-environment-variables-0.4.4.tgz", + "integrity": "sha512-bJILBtn5a11SmtR2j/3mBOjX4K3weC6cq+NNZ7hG22wCAqpc3qtj/iN7dSe9HDiS46lgp1nHsQgeYrea/RUe+g==", "dev": true, "license": "MIT" }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, "engines": { - "node": ">=14" + "node": ">= 0.4" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT" }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/baseline-browser-mapping": { + "version": "2.9.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.18.tgz", + "integrity": "sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA==", "dev": true, - "license": "Python-2.0" + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" } }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, + "optional": true, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" } }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", "dev": true, "license": "MIT" }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "dev": true, "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/array.prototype.reduce": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.8.tgz", - "integrity": "sha512-DwuEqgXFBwbmZSRqt3BpQigWNUoqw9Ml2dTWdF3B2zQlQX4OeUE0zyuzX0fX0IbTvjdkZbcBTU3idgpO78qkTw==", + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-array-method-boxes-properly": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "is-string": "^1.1.1" + "side-channel": "^1.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "node_modules/bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", "dev": true, "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/as-table": { - "version": "1.0.55", - "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", - "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "printable-characters": "^1.0.42" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": "~2.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "node_modules/boxen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "node_modules/boxen/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, - "node_modules/assert": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", - "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", - "dependencies": { - "object.assign": "^4.1.4", - "util": "^0.10.4" + "engines": { + "node": ">=8" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.8" + "node": ">=8" } }, - "node_modules/assert/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "node_modules/boxen/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, - "license": "ISC" + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } }, - "node_modules/assert/node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "2.0.3" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", - "dev": true, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, - "node_modules/async-each": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", - "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "license": "MIT" }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/async-limiter": { + "node_modules/browserify-cipher": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/autocomplete.js": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/autocomplete.js/-/autocomplete.js-0.36.0.tgz", - "integrity": "sha512-jEwUXnVMeCHHutUt10i/8ZiRaCb0Wo+ZyKxeGsYwBDtw6EJHqEeDrq4UwZRD8YBSvp3g6klP678il2eeiVXN2Q==", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "license": "MIT", "dependencies": { - "immediate": "^3.2.3" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "node_modules/autocomplete.js/node_modules/immediate": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", - "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/autoprefixer": { - "version": "9.8.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "picocolors": "^0.2.1", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "node_modules/autoprefixer/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/autoprefixer/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 0.10" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/browserify-sign": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "license": "Apache-2.0", "engines": { - "node": "*" + "node": ">= 0.10" } }, - "node_modules/aws4": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", - "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", - "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "slash": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "pako": "~1.0.5" } }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, - "engines": { - "node": ">=10" + "bin": { + "browserslist": "cli.js" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/babel-jest/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, - "node_modules/babel-loader": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz", - "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-json/-/buffer-json-2.0.0.tgz", + "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-require": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-2.1.8.tgz", + "integrity": "sha512-oOEg3A0hy/YzvNWNowtKD0pmhZKseOFweCbgyMqTIih4gRY1nJWsvrOCT27L9NbIyL5jMjTFrAUpGxxpW68Puw==", "dev": true, "license": "MIT", - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.4", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 8.9" - }, "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" + "esbuild": ">=0.13" } }, - "node_modules/babel-loader/node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + "node": ">= 0.8" } }, - "node_modules/babel-loader/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, "engines": { "node": ">=8" } }, - "node_modules/babel-loader/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "p-locate": "^4.1.0" + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" }, "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/babel-loader/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/cacache/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^6.0.0" - }, + "license": "ISC", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/babel-loader/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/cacache/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "p-try": "^2.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/babel-loader/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/cacache/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "p-limit": "^2.2.0" + "yallist": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/babel-loader/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/cacache/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, "license": "MIT", "dependencies": { - "find-up": "^4.0.0" + "minipass": "^3.0.0", + "yallist": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "license": "MIT", - "dependencies": { - "object.assign": "^4.1.0" + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/cacache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "glob": "^7.1.3" }, - "engines": { - "node": ">=8" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "node_modules/cacache/node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "node_modules/cacache/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, + "license": "ISC", "engines": { - "node": ">= 10.14.2" + "node": ">=8" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "node_modules/cache-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-3.0.1.tgz", + "integrity": "sha512-HzJIvGiGqYsFUrMjAJNDbVZoG7qQA+vy9AIoKs7s9DscNfki0I589mf2w6/tW+kkFH3zyiknoWV5Jdynu6b/zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" + "buffer-json": "^2.0.0", + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.2.3", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6.9.0" }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "webpack": "^4.0.0" } }, - "node_modules/babel-plugin-transform-inline-environment-variables": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-environment-variables/-/babel-plugin-transform-inline-environment-variables-0.4.4.tgz", - "integrity": "sha512-bJILBtn5a11SmtR2j/3mBOjX4K3weC6cq+NNZ7hG22wCAqpc3qtj/iN7dSe9HDiS46lgp1nHsQgeYrea/RUe+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", - "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "node_modules/cache-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" + "minimist": "^1.2.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "node_modules/cache-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "^26.6.2", - "babel-preset-current-node-syntax": "^1.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=4.0.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/cache-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "license": "MIT", "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 4" } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.0" + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "pump": "^3.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "node_modules/cacheable-request/node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT" }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "node_modules/cacheable-request/node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", "dev": true, "license": "MIT", - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.7", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz", - "integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT" - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "tweetnacl": "^0.14.3" + "json-buffer": "3.0.0" } }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", "dev": true, - "license": "Unlicense", + "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=8" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/cacheable-request/node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "license": "MIT", "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" }, "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "file-uri-to-path": "1.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", + "node_modules/call-me-maybe": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", + "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", "dev": true, "license": "MIT" }, - "node_modules/bn.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", - "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" + "callsites": "^2.0.0" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=4" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">=4" } }, - "node_modules/body-parser/node_modules/ms": { + "node_modules/caller-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", "dev": true, "license": "MIT", "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" - }, - "node_modules/boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/boxen/node_modules/chalk": { + "node_modules/camel-case": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" + "no-case": "^2.2.0", + "upper-case": "^1.1.1" } }, - "node_modules/boxen/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/caniuse-lite": { + "version": "1.0.30001766", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz", + "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dev": true, - "license": "MIT", + "node_modules/chevrotain": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-6.5.0.tgz", + "integrity": "sha512-BwqQ/AgmKJ8jcMEjaSnfMybnKMgGTrtDKowfTP3pX4jwVy0kNjRsT/AP6h+wC3+3NC+X8X15VWBnTCQlX+wQFg==", + "license": "Apache-2.0", "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "regexp-to-ast": "0.4.0" } }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "node_modules/browserify-rsa": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", - "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "license": "MIT", - "dependencies": { - "bn.js": "^5.2.1", - "randombytes": "^2.1.0", - "safe-buffer": "^5.2.1" - }, "engines": { - "node": ">= 0.10" + "node": ">=6.0" } }, - "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "dev": true, + "license": "MIT", "dependencies": { - "bn.js": "^5.2.2", - "browserify-rsa": "^4.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.6.1", "inherits": "^2.0.4", - "parse-asn1": "^5.1.9", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" }, "engines": { "node": ">= 0.10" } }, - "node_modules/browserify-sign/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/clean-css": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", + "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" } }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/browserify-sign/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", "dev": true, "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "license": "ISC", "dependencies": { - "safe-buffer": "~5.1.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" } }, - "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/cliui/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true, "license": "MIT" }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "dev": true, "license": "MIT", - "dependencies": { - "pako": "~1.0.5" + "engines": { + "node": ">=4" } }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "node_modules/cliui/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=6" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "node_modules/cliui/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "license": "MIT", "dependencies": { - "fast-json-stable-stringify": "2.x" + "ansi-regex": "^4.1.0" }, "engines": { - "node": ">= 6" + "node": ">=6" } }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "node-int64": "^0.4.0" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "dev": true, "license": "MIT", - "engines": { - "node": "*" + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", "dev": true, "license": "MIT", + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, "engines": { - "node": ">=0.10" + "node": ">= 4.0" } }, - "node_modules/buffer-json": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-json/-/buffer-json-2.0.0.tgz", - "integrity": "sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw==", + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "engines": { - "node": ">=0.2.0" + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" } }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true, "license": "MIT" }, - "node_modules/bundle-require": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-2.1.8.tgz", - "integrity": "sha512-oOEg3A0hy/YzvNWNowtKD0pmhZKseOFweCbgyMqTIih4gRY1nJWsvrOCT27L9NbIyL5jMjTFrAUpGxxpW68Puw==", + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "dev": true, "license": "MIT", - "peerDependencies": { - "esbuild": ">=0.13" + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, "engines": { "node": ">= 0.8" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 12.0.0" } }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } + "license": "MIT" }, - "node_modules/cacache/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "mime-db": ">= 1.43.0 < 2" }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/cacache/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/cacache/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" + "ms": "2.0.0" } }, - "node_modules/cacache/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, + "engines": [ + "node >= 0.8" + ], "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/cacache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/configstore/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "semver": "^6.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cacache/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.8" } }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", "dev": true, "license": "MIT", - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": "^14.18.0 || >=16.10.0" } }, - "node_modules/cache-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-3.0.1.tgz", - "integrity": "sha512-HzJIvGiGqYsFUrMjAJNDbVZoG7qQA+vy9AIoKs7s9DscNfki0I589mf2w6/tW+kkFH3zyiknoWV5Jdynu6b/zw==", + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", "dev": true, "license": "MIT", "dependencies": { - "buffer-json": "^2.0.0", - "find-cache-dir": "^2.1.0", - "loader-utils": "^1.2.3", - "mkdirp": "^0.5.1", - "neo-async": "^2.6.1", - "schema-utils": "^1.0.0" + "bluebird": "^3.1.1" }, "engines": { - "node": ">= 6.9.0" - }, - "peerDependencies": { - "webpack": "^4.0.0" + "node": ">= 0.10.0" } }, - "node_modules/cache-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } + "license": "MIT" }, - "node_modules/cache-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "safe-buffer": "5.2.1" }, "engines": { - "node": ">=4.0.0" + "node": ">= 0.6" } }, - "node_modules/cache-loader/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - }, "engines": { - "node": ">= 4" + "node": ">= 0.6" } }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/cacheable-request/node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "dev": true, "license": "MIT" }, - "node_modules/cacheable-request/node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "deprecated": "This package is no longer supported.", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "json-buffer": "3.0.0" + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" } }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "node_modules/copy-concurrently/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" } }, - "node_modules/cacheable-request/node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "node_modules/copy-webpack-plugin": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", + "integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" + "cacache": "^12.0.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.1", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "webpack-log": "^2.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 6.9.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/call-bind-apply-helpers": { + "node_modules/copy-webpack-plugin/node_modules/array-union": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "array-uniq": "^1.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/copy-webpack-plugin/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" } }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", - "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==", + "node_modules/copy-webpack-plugin/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "node_modules/copy-webpack-plugin/node_modules/dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", "dev": true, "license": "MIT", "dependencies": { - "callsites": "^2.0.0" + "path-type": "^3.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", "dev": true, "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.0" + }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==", "dev": true, "license": "MIT", "dependencies": { - "caller-callsite": "^2.0.0" + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/copy-webpack-plugin/node_modules/ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-webpack-plugin/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "node_modules/copy-webpack-plugin/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/copy-webpack-plugin/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/caniuse-api": { + "node_modules/copy-webpack-plugin/node_modules/path-type": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001760", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", - "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", + "node_modules/copy-webpack-plugin/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "node_modules/copy-webpack-plugin/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { - "rsvp": "^4.8.4" + "glob": "^7.1.3" }, - "engines": { - "node": "6.* || 8.* || >= 10.*" + "bin": { + "rimraf": "bin.js" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, - "license": "MIT/X11", + "license": "MIT", "dependencies": { - "traverse": ">=0.3.0 <0.4" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" }, "engines": { - "node": "*" + "node": ">= 4" } }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/copy-webpack-plugin/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" + "randombytes": "^2.1.0" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/chalk/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/copy-webpack-plugin/node_modules/ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "color-name": "1.1.3" + "figgy-pudding": "^3.5.1" } }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/core-js": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.48.0.tgz", + "integrity": "sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "engines": { - "node": ">=0.8.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/core-js-compat": { + "version": "3.48.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.48.0.tgz", + "integrity": "sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/chevrotain": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-6.5.0.tgz", - "integrity": "sha512-BwqQ/AgmKJ8jcMEjaSnfMybnKMgGTrtDKowfTP3pX4jwVy0kNjRsT/AP6h+wC3+3NC+X8X15VWBnTCQlX+wQFg==", - "license": "Apache-2.0", "dependencies": { - "regexp-to-ast": "0.4.0" + "sprintf-js": "~1.0.2" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/cosmiconfig/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" }, "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=4" + } + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/chownr": { + "node_modules/cosmiconfig/node_modules/resolve-from": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=4" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6.0" + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" } }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, "license": "MIT" }, - "node_modules/cipher-base": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", - "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.2" - }, - "engines": { - "node": ">= 0.10" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, - "node_modules/cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, "license": "MIT" }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", "dev": true, "license": "MIT", "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" } }, - "node_modules/clean-css": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { - "source-map": "~0.6.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">= 4.0" + "node": ">= 8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", "dev": true, "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, "engines": { - "node": ">=6" + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "node_modules/css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/clone-deep": { + "node_modules/css-declaration-sorter": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", + "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "postcss": "^7.0.1", + "timsort": "^0.3.0" }, "engines": { - "node": ">=6" + "node": ">4" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "node_modules/css-declaration-sorter/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/css-declaration-sorter/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "mimic-response": "^1.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "node_modules/css-loader": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", + "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", "dev": true, "license": "MIT", + "dependencies": { + "camelcase": "^5.2.0", + "icss-utils": "^4.1.0", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.14", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^2.0.6", + "postcss-modules-scope": "^2.1.0", + "postcss-modules-values": "^2.0.0", + "postcss-value-parser": "^3.3.0", + "schema-utils": "^1.0.0" + }, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" } }, - "node_modules/coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "node_modules/css-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" + "minimist": "^1.2.0" }, - "engines": { - "node": ">= 4.0" + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/collect-v8-coverage": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", - "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "node_modules/css-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0" } }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "node_modules/css-loader/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } + "license": "ISC" }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/css-loader/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/css-loader/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "node_modules/css-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" } }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/css-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "css": "^2.0.0" } }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", "dev": true, - "license": "MIT" + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", "dev": true, "license": "MIT" }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", "dev": true, "license": "MIT", "dependencies": { - "delayed-stream": "~1.0.0" + "mdn-data": "2.0.4", + "source-map": "^0.6.1" }, "engines": { - "node": ">= 0.8" + "node": ">=8.0.0" } }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true, - "license": "MIT" - }, - "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true, - "license": "MIT", + "node": ">= 6" + }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, "license": "MIT", - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" + "bin": { + "cssesc": "bin/cssesc" }, "engines": { - "node": ">= 10" + "node": ">=4" } }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/cssnano": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", + "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "cosmiconfig": "^5.0.0", + "cssnano-preset-default": "^4.0.8", + "is-resolvable": "^1.0.0", + "postcss": "^7.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" } }, - "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "node_modules/cssnano-preset-default": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", + "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" + "css-declaration-sorter": "^4.0.1", + "cssnano-util-raw-cache": "^4.0.1", + "postcss": "^7.0.0", + "postcss-calc": "^7.0.1", + "postcss-colormin": "^4.0.3", + "postcss-convert-values": "^4.0.1", + "postcss-discard-comments": "^4.0.2", + "postcss-discard-duplicates": "^4.0.2", + "postcss-discard-empty": "^4.0.1", + "postcss-discard-overridden": "^4.0.1", + "postcss-merge-longhand": "^4.0.11", + "postcss-merge-rules": "^4.0.3", + "postcss-minify-font-values": "^4.0.2", + "postcss-minify-gradients": "^4.0.2", + "postcss-minify-params": "^4.0.2", + "postcss-minify-selectors": "^4.0.2", + "postcss-normalize-charset": "^4.0.1", + "postcss-normalize-display-values": "^4.0.2", + "postcss-normalize-positions": "^4.0.2", + "postcss-normalize-repeat-style": "^4.0.2", + "postcss-normalize-string": "^4.0.2", + "postcss-normalize-timing-functions": "^4.0.2", + "postcss-normalize-unicode": "^4.0.1", + "postcss-normalize-url": "^4.0.1", + "postcss-normalize-whitespace": "^4.0.2", + "postcss-ordered-values": "^4.1.2", + "postcss-reduce-initial": "^4.0.3", + "postcss-reduce-transforms": "^4.0.2", + "postcss-svgo": "^4.0.3", + "postcss-unique-selectors": "^4.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">=6.9.0" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/cssnano-preset-default/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/cssnano-preset-default/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "node_modules/cssnano-util-get-arguments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", + "integrity": "sha512-6RIcwmV3/cBMG8Aj5gucQRsJb4vv4I4rn6YjPbVWd5+Pn/fuG+YseGvXGk00XLkoZkaj31QOD7vMUpNPC4FIuw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "node_modules/cssnano-util-get-match": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", + "integrity": "sha512-JPMZ1TSMRUPVIqEalIBNoBtAYbi8okvcFns4O0YIhcdGebeYZK7dMyHJiQ6GqNBA9kE0Hym4Aqym5rPdsV/4Cw==", "dev": true, - "engines": [ - "node >= 0.8" - ], "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/concat-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/cssnano-util-raw-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", + "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "postcss": "^7.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/concat-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/cssnano-util-raw-cache/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/cssnano-util-raw-cache/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "node_modules/cssnano-util-same-parent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", + "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/configstore/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/cssnano/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/cssnano/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^6.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=8" + "node": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "css-tree": "^1.1.2" }, "engines": { - "node": ">= 0.10.0" + "node": ">=8.0.0" } }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", "dev": true, "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, "engines": { - "node": ">=0.8" + "node": ">=8.0.0" } }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } + "license": "CC0-1.0" }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, "license": "MIT" }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "node_modules/cyclist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", + "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", "dev": true, - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true + "license": "MIT" }, - "node_modules/consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "deprecated": "Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog", + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "license": "MIT", "dependencies": { - "bluebird": "^3.1.1" + "assert-plus": "^1.0.0" }, "engines": { - "node": ">= 0.10.0" + "node": ">=0.10" } }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "5.2.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "*" + } }, - "node_modules/copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "deprecated": "This package is no longer supported.", + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/copy-concurrently/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "license": "MIT", + "engines": { + "node": ">=0.10" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", "dev": true, "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/copy-webpack-plugin": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz", - "integrity": "sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ==", + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", "dev": true, "license": "MIT", "dependencies": { - "cacache": "^12.0.3", - "find-cache-dir": "^2.1.0", - "glob-parent": "^3.1.0", - "globby": "^7.1.1", - "is-glob": "^4.0.1", - "loader-utils": "^1.2.3", - "minimatch": "^3.0.4", - "normalize-path": "^3.0.0", - "p-limit": "^2.2.1", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "webpack-log": "^2.0.0" + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" }, "engines": { - "node": ">= 6.9.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/copy-webpack-plugin/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "license": "MIT", - "dependencies": { - "array-uniq": "^1.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0" } }, - "node_modules/copy-webpack-plugin/node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, - "node_modules/copy-webpack-plugin/node_modules/cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", "dev": true, - "license": "ISC", - "dependencies": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/copy-webpack-plugin/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "license": "ISC" - }, - "node_modules/copy-webpack-plugin/node_modules/dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "node_modules/default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "path-type": "^3.0.0" + "execa": "^1.0.0", + "ip-regex": "^2.1.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } + "license": "MIT" }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/copy-webpack-plugin/node_modules/globby": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", - "integrity": "sha512-yANWAN2DUcBtuus5Cpd+SKROzXHs2iVXFZt/Ykrfz6SAXqacLX25NZpltE+39ceMexYF4TtEadjuSTw8+3wX4g==", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "license": "MIT", "dependencies": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/copy-webpack-plugin/node_modules/ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true, - "license": "MIT" - }, - "node_modules/copy-webpack-plugin/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "is-descriptor": "^0.1.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/copy-webpack-plugin/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" }, "engines": { - "node": ">=4.0.0" + "node": ">=6" } }, - "node_modules/copy-webpack-plugin/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/del/node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "array-uniq": "^1.0.1" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/copy-webpack-plugin/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/del/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", "dev": true, "license": "MIT", "dependencies": { - "pify": "^3.0.0" + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/copy-webpack-plugin/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/del/node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/copy-webpack-plugin/node_modules/rimraf": { + "node_modules/del/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", @@ -9284,7478 +8518,2594 @@ "rimraf": "bin.js" } }, - "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - }, "engines": { - "node": ">= 4" + "node": ">=0.4.0" } }, - "node_modules/copy-webpack-plugin/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "license": "MIT", "dependencies": { - "randombytes": "^2.1.0" + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "node_modules/copy-webpack-plugin/node_modules/slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==", + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/copy-webpack-plugin/node_modules/ssri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", "dev": true, "license": "ISC", "dependencies": { - "figgy-pudding": "^3.5.1" + "asap": "^2.0.0", + "wrappy": "1" } }, - "node_modules/core-js": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", - "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" } }, - "node_modules/core-js-compat": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", - "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.28.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" } }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, "license": "MIT" }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "license": "MIT", "dependencies": { - "object-assign": "^4", - "vary": "^1" + "path-type": "^4.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", "dev": true, - "license": "MIT", - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", "dev": true, "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" } }, - "node_modules/cosmiconfig/node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "node_modules/dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", "dev": true, "license": "MIT", "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" + "buffer-indexof": "^1.0.0" } }, - "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "node_modules/docsearch.js": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/docsearch.js/-/docsearch.js-2.6.3.tgz", + "integrity": "sha512-GN+MBozuyz664ycpZY0ecdQE0ND/LSgJKhTLA0/v3arIS3S1Rpf2OJz6A35ReMsm91V5apcmzr5/kM84cvUg+A==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @docsearch/js.", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "algoliasearch": "^3.24.5", + "autocomplete.js": "0.36.0", + "hogan.js": "^3.0.2", + "request": "^2.87.0", + "stack-utils": "^1.0.1", + "to-factory": "^1.0.0", + "zepto": "^1.2.0" } }, - "node_modules/cosmiconfig/node_modules/resolve-from": { + "node_modules/doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" + "dependencies": { + "esutils": "^2.0.2" }, "engines": { - "node": ">=0.8" + "node": ">=6.0.0" } }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "dev": true, "license": "MIT", "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" + "utila": "~0.4" } }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" + "domelementtype": "^2.0.1", + "entities": "^2.0.0" } }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true, "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "engines": { + "node": ">=0.4", + "npm": ">=1.2" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", "dev": true, - "license": "MIT" + "license": "BSD-2-Clause" }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" + "domelementtype": "^2.2.0" }, "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/domhandler/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "is-obj": "^2.0.0" }, "engines": { - "node": ">= 8" + "node": ">=8" } }, - "node_modules/crypto-browserify": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", - "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { - "browserify-cipher": "^1.0.1", - "browserify-sign": "^4.2.3", - "create-ecdh": "^4.0.4", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "diffie-hellman": "^5.0.3", - "hash-base": "~3.0.4", - "inherits": "^2.0.4", - "pbkdf2": "^3.1.2", - "public-encrypt": "^4.0.3", - "randombytes": "^2.1.0", - "randomfill": "^1.0.4" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" }, "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.4" } }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "BSD-3-Clause" }, - "node_modules/css": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", - "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "source-map": "^0.6.1", - "source-map-resolve": "^0.5.2", - "urix": "^0.1.0" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" } }, - "node_modules/css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==", + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "license": "MIT", - "engines": { - "node": "*" + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, - "node_modules/css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.279", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.279.tgz", + "integrity": "sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg==", + "dev": true, + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - }, - "engines": { - "node": ">4" + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/css-declaration-sorter/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/css-declaration-sorter/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 4" } }, - "node_modules/css-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-2.1.1.tgz", - "integrity": "sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==", + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", - "dependencies": { - "camelcase": "^5.2.0", - "icss-utils": "^4.1.0", - "loader-utils": "^1.2.3", - "normalize-path": "^3.0.0", - "postcss": "^7.0.14", - "postcss-modules-extract-imports": "^2.0.0", - "postcss-modules-local-by-default": "^2.0.6", - "postcss-modules-scope": "^2.1.0", - "postcss-modules-values": "^2.0.0", - "postcss-value-parser": "^3.3.0", - "schema-utils": "^1.0.0" - }, "engines": { - "node": ">= 6.9.0" - }, - "peerDependencies": { - "webpack": "^4.0.0" + "node": ">= 0.8" } }, - "node_modules/css-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "once": "^1.4.0" } }, - "node_modules/css-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "dev": true, - "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.9.0" } }, - "node_modules/css-loader/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/css-loader/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=6.0.0" + "node": ">=0.12" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/css-loader/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/css-loader/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "node_modules/env-cmd": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", + "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "commander": "^4.0.0", + "cross-spawn": "^7.0.0" + }, + "bin": { + "env-cmd": "bin/env-cmd.js" }, "engines": { - "node": ">= 4" + "node": ">=8.0.0" } }, - "node_modules/css-parse": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", - "integrity": "sha512-UNIFik2RgSbiTwIW1IsFwXWn6vs+bYdq83LKTSOsx7NJR7WII9dxewkHLltfTLVppoUApHV0118a4RZRI9FLwA==", + "node_modules/env-cmd/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, "license": "MIT", - "dependencies": { - "css": "^2.0.0" + "engines": { + "node": ">= 6" } }, - "node_modules/css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "node_modules/envify": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz", + "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "node_modules/css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" + "esprima": "^4.0.0", + "through": "~2.3.4" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "bin": { + "envify": "bin/envify" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", "dev": true, "license": "MIT", "bin": { - "cssesc": "bin/cssesc" + "envinfo": "dist/cli.js" }, "engines": { "node": ">=4" } }, - "node_modules/cssnano": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", - "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "license": "MIT", "dependencies": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.8", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" + "prr": "~1.0.1" }, - "engines": { - "node": ">=6.9.0" + "bin": { + "errno": "cli.js" } }, - "node_modules/cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "license": "MIT", "dependencies": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - }, - "engines": { - "node": ">=6.9.0" + "is-arrayish": "^0.2.1" } }, - "node_modules/cssnano-preset-default/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/cssnano-preset-default/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" }, "engines": { - "node": ">=6.0.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha512-6RIcwmV3/cBMG8Aj5gucQRsJb4vv4I4rn6YjPbVWd5+Pn/fuG+YseGvXGk00XLkoZkaj31QOD7vMUpNPC4FIuw==", + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">= 0.4" } }, - "node_modules/cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha512-JPMZ1TSMRUPVIqEalIBNoBtAYbi8okvcFns4O0YIhcdGebeYZK7dMyHJiQ6GqNBA9kE0Hym4Aqym5rPdsV/4Cw==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">= 0.4" } }, - "node_modules/cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.0" + "es-errors": "^1.3.0" }, "engines": { - "node": ">=6.9.0" + "node": ">= 0.4" } }, - "node_modules/cssnano-util-raw-cache/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/cssnano-util-raw-cache/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 0.4" } }, - "node_modules/cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/cssnano/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { - "node": ">=6.0.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true, - "license": "MIT", - "dependencies": { - "css-tree": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } + "license": "MIT" }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "node_modules/esbuild": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.7.tgz", + "integrity": "sha512-+u/msd6iu+HvfysUPkZ9VHm83LImmSNnecYPfFI01pQ7TTcsFR+V0BkybZX7mPtIaI7LCrse6YRj+v3eraJSgw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" + "bin": { + "esbuild": "bin/esbuild" }, - "engines": { - "node": ">=8.0.0" + "optionalDependencies": { + "esbuild-android-arm64": "0.14.7", + "esbuild-darwin-64": "0.14.7", + "esbuild-darwin-arm64": "0.14.7", + "esbuild-freebsd-64": "0.14.7", + "esbuild-freebsd-arm64": "0.14.7", + "esbuild-linux-32": "0.14.7", + "esbuild-linux-64": "0.14.7", + "esbuild-linux-arm": "0.14.7", + "esbuild-linux-arm64": "0.14.7", + "esbuild-linux-mips64le": "0.14.7", + "esbuild-linux-ppc64le": "0.14.7", + "esbuild-netbsd-64": "0.14.7", + "esbuild-openbsd-64": "0.14.7", + "esbuild-sunos-64": "0.14.7", + "esbuild-windows-32": "0.14.7", + "esbuild-windows-64": "0.14.7", + "esbuild-windows-arm64": "0.14.7" } }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "node_modules/esbuild-android-arm64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.7.tgz", + "integrity": "sha512-9/Q1NC4JErvsXzJKti0NHt+vzKjZOgPIjX/e6kkuCzgfT/GcO3FVBcGIv4HeJG7oMznE6KyKhvLrFgt7CdU2/w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/cssstyle": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", - "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "node_modules/esbuild-darwin-64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.7.tgz", + "integrity": "sha512-Z9X+3TT/Xj+JiZTVlwHj2P+8GoiSmUnGVz0YZTSt8WTbW3UKw5Pw2ucuJ8VzbD2FPy0jbIKJkko/6CMTQchShQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^3.2.0", - "rrweb-cssom": "^0.8.0" - }, - "engines": { - "node": ">=18" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/cssstyle/node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.7.tgz", + "integrity": "sha512-68e7COhmwIiLXBEyxUxZSSU0akgv8t3e50e2QOtKdBUE0F6KIRISzFntLe2rYlNqSsjGWsIO6CCc9tQxijjSkw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "node_modules/esbuild-freebsd-64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.7.tgz", + "integrity": "sha512-76zy5jAjPiXX/S3UvRgG85Bb0wy0zv/J2lel3KtHi4V7GUTBfhNUPt0E5bpSXJ6yMT7iThhnA5rOn+IJiUcslQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.7.tgz", + "integrity": "sha512-lSlYNLiqyzd7qCN5CEOmLxn7MhnGHPcu5KuUYOG1i+t5A6q7LgBmfYC9ZHJBoYyow3u4CNu79AWHbvVLpE/VQQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/cyclist": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", - "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", + "node_modules/esbuild-linux-32": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.7.tgz", + "integrity": "sha512-Vk28u409wVOXqTaT6ek0TnfQG4Ty1aWWfiysIaIRERkNLhzLhUf4i+qJBN8mMuGTYOkE40F0Wkbp6m+IidOp2A==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "node_modules/esbuild-linux-64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.7.tgz", + "integrity": "sha512-+Lvz6x+8OkRk3K2RtZwO+0a92jy9si9cUea5Zoru4yJ/6EQm9ENX5seZE0X9DTwk1dxJbjmLsJsd3IoowyzgVg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/data-urls": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", - "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "node_modules/esbuild-linux-arm": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.7.tgz", + "integrity": "sha512-OzpXEBogbYdcBqE4uKynuSn5YSetCvK03Qv1HcOY1VN6HmReuatjJ21dCH+YPHSpMEF0afVCnNfffvsGEkxGJQ==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0" - }, - "engines": { - "node": ">=18" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "node_modules/esbuild-linux-arm64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.7.tgz", + "integrity": "sha512-kJd5beWSqteSAW086qzCEsH6uwpi7QRIpzYWHzEYwKKu9DiG1TwIBegQJmLpPsLp4v5RAFjea0JAmAtpGtRpqg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.7.tgz", + "integrity": "sha512-mFWpnDhZJmj/h7pxqn1GGDsKwRfqtV7fx6kTF5pr4PfXe8pIaTERpwcKkoCwZUkWAOmUEjMIUAvFM72A6hMZnA==", + "cpu": [ + "mips64el" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/date-format": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", - "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/dayjs": { - "version": "1.11.19", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", - "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true, - "license": "MIT" - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", - "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/default-gateway/node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway/node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/default-gateway/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/default-gateway/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/default-gateway/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", - "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/des.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", - "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT" - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", - "dev": true, - "license": "MIT" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", - "dev": true, - "license": "MIT" - }, - "node_modules/dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-indexof": "^1.0.0" - } - }, - "node_modules/docsearch.js": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/docsearch.js/-/docsearch.js-2.6.3.tgz", - "integrity": "sha512-GN+MBozuyz664ycpZY0ecdQE0ND/LSgJKhTLA0/v3arIS3S1Rpf2OJz6A35ReMsm91V5apcmzr5/kM84cvUg+A==", - "deprecated": "This package has been deprecated and is no longer maintained. Please use @docsearch/js.", - "dev": true, - "license": "MIT", - "dependencies": { - "algoliasearch": "^3.24.5", - "autocomplete.js": "0.36.0", - "hogan.js": "^3.0.2", - "request": "^2.87.0", - "stack-utils": "^1.0.1", - "to-factory": "^1.0.0", - "zepto": "^1.2.0" - } - }, - "node_modules/docsearch.js/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/docsearch.js/node_modules/stack-utils": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", - "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "license": "MIT", - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/dom-serializer/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/dom-serializer/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", - "dev": true - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, - "node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "license": "MIT", - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domhandler/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/duplexer2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexer2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/duplexify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/duplexify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, - "license": "ISC" - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/engine.io": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", - "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.7.2", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/engine.io/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/enhanced-resolve": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", - "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/ent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", - "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "punycode": "^1.4.1", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-cmd": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", - "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^4.0.0", - "cross-spawn": "^7.0.0" - }, - "bin": { - "env-cmd": "bin/env-cmd.js" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/env-cmd/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/envify": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz", - "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esprima": "^4.0.0", - "through": "~2.3.4" - }, - "bin": { - "envify": "bin/envify" - } - }, - "node_modules/envinfo": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", - "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", - "dev": true, - "license": "MIT", - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.7.tgz", - "integrity": "sha512-+u/msd6iu+HvfysUPkZ9VHm83LImmSNnecYPfFI01pQ7TTcsFR+V0BkybZX7mPtIaI7LCrse6YRj+v3eraJSgw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "optionalDependencies": { - "esbuild-android-arm64": "0.14.7", - "esbuild-darwin-64": "0.14.7", - "esbuild-darwin-arm64": "0.14.7", - "esbuild-freebsd-64": "0.14.7", - "esbuild-freebsd-arm64": "0.14.7", - "esbuild-linux-32": "0.14.7", - "esbuild-linux-64": "0.14.7", - "esbuild-linux-arm": "0.14.7", - "esbuild-linux-arm64": "0.14.7", - "esbuild-linux-mips64le": "0.14.7", - "esbuild-linux-ppc64le": "0.14.7", - "esbuild-netbsd-64": "0.14.7", - "esbuild-openbsd-64": "0.14.7", - "esbuild-sunos-64": "0.14.7", - "esbuild-windows-32": "0.14.7", - "esbuild-windows-64": "0.14.7", - "esbuild-windows-arm64": "0.14.7" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.7.tgz", - "integrity": "sha512-9/Q1NC4JErvsXzJKti0NHt+vzKjZOgPIjX/e6kkuCzgfT/GcO3FVBcGIv4HeJG7oMznE6KyKhvLrFgt7CdU2/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.7.tgz", - "integrity": "sha512-Z9X+3TT/Xj+JiZTVlwHj2P+8GoiSmUnGVz0YZTSt8WTbW3UKw5Pw2ucuJ8VzbD2FPy0jbIKJkko/6CMTQchShQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.7.tgz", - "integrity": "sha512-68e7COhmwIiLXBEyxUxZSSU0akgv8t3e50e2QOtKdBUE0F6KIRISzFntLe2rYlNqSsjGWsIO6CCc9tQxijjSkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.7.tgz", - "integrity": "sha512-76zy5jAjPiXX/S3UvRgG85Bb0wy0zv/J2lel3KtHi4V7GUTBfhNUPt0E5bpSXJ6yMT7iThhnA5rOn+IJiUcslQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.7.tgz", - "integrity": "sha512-lSlYNLiqyzd7qCN5CEOmLxn7MhnGHPcu5KuUYOG1i+t5A6q7LgBmfYC9ZHJBoYyow3u4CNu79AWHbvVLpE/VQQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.7.tgz", - "integrity": "sha512-Vk28u409wVOXqTaT6ek0TnfQG4Ty1aWWfiysIaIRERkNLhzLhUf4i+qJBN8mMuGTYOkE40F0Wkbp6m+IidOp2A==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.7.tgz", - "integrity": "sha512-+Lvz6x+8OkRk3K2RtZwO+0a92jy9si9cUea5Zoru4yJ/6EQm9ENX5seZE0X9DTwk1dxJbjmLsJsd3IoowyzgVg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.7.tgz", - "integrity": "sha512-OzpXEBogbYdcBqE4uKynuSn5YSetCvK03Qv1HcOY1VN6HmReuatjJ21dCH+YPHSpMEF0afVCnNfffvsGEkxGJQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.7.tgz", - "integrity": "sha512-kJd5beWSqteSAW086qzCEsH6uwpi7QRIpzYWHzEYwKKu9DiG1TwIBegQJmLpPsLp4v5RAFjea0JAmAtpGtRpqg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.7.tgz", - "integrity": "sha512-mFWpnDhZJmj/h7pxqn1GGDsKwRfqtV7fx6kTF5pr4PfXe8pIaTERpwcKkoCwZUkWAOmUEjMIUAvFM72A6hMZnA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.7.tgz", - "integrity": "sha512-wM7f4M0bsQXfDL4JbbYD0wsr8cC8KaQ3RPWc/fV27KdErPW7YsqshZZSjDV0kbhzwpNNdhLItfbaRT8OE8OaKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.7.tgz", - "integrity": "sha512-J/afS7woKyzGgAL5FlgvMyqgt5wQ597lgsT+xc2yJ9/7BIyezeXutXqfh05vszy2k3kSvhLesugsxIA71WsqBw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ] - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.7.tgz", - "integrity": "sha512-7CcxgdlCD+zAPyveKoznbgr3i0Wnh0L8BDGRCjE/5UGkm5P/NQko51tuIDaYof8zbmXjjl0OIt9lSo4W7I8mrw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.7.tgz", - "integrity": "sha512-GKCafP2j/KUljVC3nesw1wLFSZktb2FGCmoT1+730zIF5O6hNroo0bSEofm6ZK5mNPnLiSaiLyRB9YFgtkd5Xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ] - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.7.tgz", - "integrity": "sha512-5I1GeL/gZoUUdTPA0ws54bpYdtyeA2t6MNISalsHpY269zK8Jia/AXB3ta/KcDHv2SvNwabpImeIPXC/k0YW6A==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.7.tgz", - "integrity": "sha512-CIGKCFpQOSlYsLMbxt8JjxxvVw9MlF1Rz2ABLVfFyHUF5OeqHD5fPhGrCVNaVrhO8Xrm+yFmtjcZudUGr5/WYQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.7.tgz", - "integrity": "sha512-eOs1eSivOqN7cFiRIukEruWhaCf75V0N8P0zP7dh44LIhLl8y6/z++vv9qQVbkBm5/D7M7LfCfCTmt1f1wHOCw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", - "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-jasmine": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-4.2.2.tgz", - "integrity": "sha512-nALbewRk63uz28UGNhUTJyd6GofXxVNFpWFNAwr9ySc6kpSRIoO4suwZqIYz3cfJmCacilmjp7+1Ocjr7zRagA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8", - "npm": ">=6" - } - }, - "node_modules/eslint-plugin-jest": { - "version": "27.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", - "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/utils": "^5.10.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", - "eslint": "^7.0.0 || ^8.0.0", - "jest": "*" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-jsdoc": { - "version": "50.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", - "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@es-joy/jsdoccomment": "~0.50.2", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.4.1", - "escape-string-regexp": "^4.0.0", - "espree": "^10.3.0", - "esquery": "^1.6.0", - "parse-imports-exports": "^0.2.4", - "semver": "^7.7.2", - "spdx-expression-parse": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-license-header": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.6.1.tgz", - "integrity": "sha512-9aIz8q3OaMr1/uQmCGCWySjTs5nEXUJexNegz/8lluNcZbEl82Ag1Vyr1Hu3oIveRW1NbXDPs6nu4zu9mbrmWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "requireindex": "^1.2.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", - "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, - "node_modules/events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/eventsource": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", - "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/exceljs": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.4.0.tgz", - "integrity": "sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "archiver": "^5.0.0", - "dayjs": "^1.8.34", - "fast-csv": "^4.3.1", - "jszip": "^3.10.1", - "readable-stream": "^3.6.0", - "saxes": "^5.0.1", - "tmp": "^0.2.0", - "unzipper": "^0.10.11", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=8.3.0" - } - }, - "node_modules/exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT" - }, - "node_modules/fast-csv": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz", - "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@fast-csv/format": "4.3.5", - "@fast-csv/parse": "4.3.6" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "deprecated": "This module is no longer supported.", - "dev": true, - "license": "ISC" - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", - "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "loader-utils": "^1.0.2", - "schema-utils": "^1.0.0" - }, - "engines": { - "node": ">= 6.9.0" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } - }, - "node_modules/file-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/file-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/file-loader/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/finalhandler/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "node_modules/flush-write-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/flush-write-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/flush-write-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/flush-write-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/foreach": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", - "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", - "dev": true, - "license": "MIT" - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", - "dev": true, - "license": "MIT", - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/from2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/from2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/from2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/from2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "node_modules/fs-write-stream-atomic/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-write-stream-atomic/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/fs-write-stream-atomic/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-write-stream-atomic/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fstream/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/full-icu": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/full-icu/-/full-icu-1.5.0.tgz", - "integrity": "sha512-BxB2otKUSFyvENjbI8EtQscpiPOEnhrf5V4MVpa6PjzsrLmdKKUUhulbydsfKS4ve6cGXNVRLlrOjizby/ZfDA==", - "dev": true, - "hasInstallScript": true, - "license": "Unicode-DFS-2016", - "dependencies": { - "yauzl": "^2.10.0" - }, - "bin": { - "full-icu": "node-full-icu.js", - "node-full-icu-path": "node-icu-data.js" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==", - "dev": true, - "license": "BSD" - }, - "node_modules/global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, - "node_modules/global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "1.3.7" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/got/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/gray-matter": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", - "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^3.13.1", - "kind-of": "^6.0.2", - "section-matter": "^1.0.0", - "strip-bom-string": "^1.0.0" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/gray-matter/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/gray-matter/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hash-base": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", - "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/hash-sum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", - "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", - "dev": true, - "license": "MIT" - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, - "node_modules/hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hogan.js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", - "integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==", - "dev": true, - "dependencies": { - "mkdirp": "0.3.0", - "nopt": "1.0.10" - }, - "bin": { - "hulk": "bin/hulk" - } - }, - "node_modules/hogan.js/node_modules/mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, - "license": "MIT/X11", - "engines": { - "node": "*" - } - }, - "node_modules/hogan.js/node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==", - "dev": true, - "license": "MIT" - }, - "node_modules/hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==", - "dev": true, - "license": "MIT" - }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/html-entities": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/html-minifier": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", - "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - }, - "bin": { - "html-minifier": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/html-minifier/node_modules/commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", - "dev": true, - "license": "MIT" - }, - "node_modules/html-minifier/node_modules/uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/html-minifier/node_modules/uglify-js/node_modules/commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/html-tags": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", - "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/htmlparser2/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/htmlparser2/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-middleware": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz", - "integrity": "sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-proxy": "^1.17.5", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", - "dev": true, - "license": "ISC" - }, - "node_modules/icss-utils": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", - "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", - "dev": true, - "license": "ISC", - "dependencies": { - "postcss": "^7.0.14" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/icss-utils/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/icss-utils/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/import-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", - "integrity": "sha512-Ew5AZzJQFqrOV5BTW3EIoHAnoie1LojZLXKcCQ/yTRyVZosBhK1x1ViYjHGf5pAFOq8ZyChZp6m/fSN7pJyZtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "import-from": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-from": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", - "integrity": "sha512-0vdnLL2wSGnhlRmzHJAg5JHjt1l2vYhzJ7tNLGbeVg0fse56tpGaH0uzH+r9Slej+BSXXEHvBKDEnVSLLE9/+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-from/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/import-local/node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==", - "dev": true, - "license": "MIT" - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true, - "license": "ISC" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/internal-ip": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", - "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==", + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.7.tgz", + "integrity": "sha512-wM7f4M0bsQXfDL4JbbYD0wsr8cC8KaQ3RPWc/fV27KdErPW7YsqshZZSjDV0kbhzwpNNdhLItfbaRT8OE8OaKA==", + "cpu": [ + "ppc64" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", - "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "node_modules/esbuild-netbsd-64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.7.tgz", + "integrity": "sha512-J/afS7woKyzGgAL5FlgvMyqgt5wQ597lgsT+xc2yJ9/7BIyezeXutXqfh05vszy2k3kSvhLesugsxIA71WsqBw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "optional": true, + "os": [ + "netbsd" + ] + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.7.tgz", + "integrity": "sha512-7CcxgdlCD+zAPyveKoznbgr3i0Wnh0L8BDGRCjE/5UGkm5P/NQko51tuIDaYof8zbmXjjl0OIt9lSo4W7I8mrw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "optional": true, + "os": [ + "openbsd" + ] }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "node_modules/esbuild-sunos-64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.7.tgz", + "integrity": "sha512-GKCafP2j/KUljVC3nesw1wLFSZktb2FGCmoT1+730zIF5O6hNroo0bSEofm6ZK5mNPnLiSaiLyRB9YFgtkd5Xg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "optional": true, + "os": [ + "sunos" + ] }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "node_modules/esbuild-windows-32": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.7.tgz", + "integrity": "sha512-5I1GeL/gZoUUdTPA0ws54bpYdtyeA2t6MNISalsHpY269zK8Jia/AXB3ta/KcDHv2SvNwabpImeIPXC/k0YW6A==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "node_modules/esbuild-windows-64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.7.tgz", + "integrity": "sha512-CIGKCFpQOSlYsLMbxt8JjxxvVw9MlF1Rz2ABLVfFyHUF5OeqHD5fPhGrCVNaVrhO8Xrm+yFmtjcZudUGr5/WYQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "node_modules/esbuild-windows-arm64": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.7.tgz", + "integrity": "sha512-eOs1eSivOqN7cFiRIukEruWhaCf75V0N8P0zP7dh44LIhLl8y6/z++vv9qQVbkBm5/D7M7LfCfCTmt1f1wHOCw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true, "license": "MIT" }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.8.0" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", "dependencies": { - "ci-info": "^2.0.0" + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { - "is-ci": "bin.js" + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==", + "node_modules/eslint-config-prettier": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", + "integrity": "sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==", "dev": true, "license": "MIT", - "dependencies": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/eslint-plugin-jsdoc": { + "version": "50.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", + "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "hasown": "^2.0.2" + "@es-joy/jsdoccomment": "~0.50.2", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.4.1", + "escape-string-regexp": "^4.0.0", + "espree": "^10.3.0", + "esquery": "^1.6.0", + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/is-data-descriptor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", - "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", - "dependencies": { - "hasown": "^2.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "node_modules/eslint-plugin-jsdoc/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-descriptor": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", - "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "dev": true, - "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.4" + "node": ">=10" } }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "node_modules/eslint-plugin-license-header": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.6.1.tgz", + "integrity": "sha512-9aIz8q3OaMr1/uQmCGCWySjTs5nEXUJexNegz/8lluNcZbEl82Ag1Vyr1Hu3oIveRW1NbXDPs6nu4zu9mbrmWA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "requireindex": "^1.2.0" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "node_modules/eslint-plugin-prettier": { + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "dev": true, "license": "MIT", - "bin": { - "is-docker": "cli.js" + "dependencies": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" }, "engines": { - "node": ">=8" + "node": "^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "is-extglob": "^2.1.1" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT", - "dependencies": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4.0" } }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=10.13.0" } }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=6" } }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": ">= 0.4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, "engines": { - "node": ">=6" + "node": ">=0.10" } }, - "node_modules/is-path-in-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", - "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT", - "dependencies": { - "is-path-inside": "^2.1.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">=6" + "node": ">=4.0" } }, - "node_modules/is-path-in-cwd/node_modules/is-path-inside": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", - "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "path-is-inside": "^1.0.2" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6" + "node": ">=4.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=8" + "node": ">=4.0" } }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4.0" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, "license": "MIT" }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.4.x" } }, - "node_modules/is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12.0.0" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=6" } }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4.8" } }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "node_modules/execa/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "node_modules/execa/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/execa/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.16" + "shebang-regex": "^1.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-typedarray": { + "node_modules/execa/node_modules/shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "node_modules/execa/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" + "isexe": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "which": "bin/which" } }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "dev": true, "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { - "node": ">=8" + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "dev": true, "license": "MIT" }, - "node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/isexe": { + "node_modules/express/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "node_modules/express/node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true, "license": "MIT" }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" + "is-descriptor": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.5.3" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" }, "engines": { - "node": ">=10" + "node": ">=8.6.0" } }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 4.9.1" } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "reusify": "^1.0.4" } }, - "node_modules/jasmine": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-5.13.0.tgz", - "integrity": "sha512-oLCXIhEb5e0zzjn9GyuvcuisvLBwUjmgz7a0RNGWKwQtJCDld4m+vwKUpAIJVLB5vbmQFdtKhT86/tIZlJ5gYw==", + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "glob": "^10.2.2", - "jasmine-core": "~5.13.0" + "websocket-driver": ">=0.5.1" }, - "bin": { - "jasmine": "bin/jasmine.js" + "engines": { + "node": ">=0.8.0" } }, - "node_modules/jasmine-core": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.13.0.tgz", - "integrity": "sha512-vsYjfh7lyqvZX5QgqKc4YH8phs7g96Z8bsdIFNEU3VqXhlHaq+vov/Fgn/sr6MiUczdZkyXRC3TX369Ll4Nzbw==", + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "deprecated": "This module is no longer supported.", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/jasmine/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jasmine/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "flat-cache": "^3.0.4" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/jasmine/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "webpack": "^4.0.0" } }, - "node_modules/javascript-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", - "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "node_modules/file-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "^26.6.3", - "import-local": "^3.0.2", - "jest-cli": "^26.6.3" + "minimist": "^1.2.0" }, "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 10.14.2" + "json5": "lib/cli.js" } }, - "node_modules/jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "node_modules/file-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">=4.0.0" } }, - "node_modules/jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "node_modules/file-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "prompts": "^2.0.1", - "yargs": "^15.4.1" - }, - "bin": { - "jest": "bin/jest.js" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 4" } }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, - "node_modules/jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", - "chalk": "^4.0.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" - }, - "engines": { - "node": ">= 10.14.2" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "ms": "2.0.0" } }, - "node_modules/jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": ">= 10.14.2" + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" } }, - "node_modules/jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" }, "engines": { - "node": ">= 10.14.2" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "glob": "^7.1.3" }, - "engines": { - "node": ">=10" + "bin": { + "rimraf": "bin.js" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" - }, + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", "engines": { - "node": ">= 10.14.2" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "node_modules/jest-environment-jsdom/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, "license": "MIT", "dependencies": { - "debug": "4" + "is-callable": "^1.2.7" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-environment-jsdom/node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", "dev": true, "license": "MIT", - "dependencies": { - "cssom": "~0.3.6" - }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/jest-environment-jsdom/node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "node_modules/foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", + "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==", "dev": true, "license": "MIT" }, - "node_modules/jest-environment-jsdom/node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, - "license": "MIT", - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "*" } }, - "node_modules/jest-environment-jsdom/node_modules/form-data": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", - "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.35" + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" }, "engines": { - "node": ">= 6" + "node": ">= 0.12" } }, - "node_modules/jest-environment-jsdom/node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "license": "MIT", - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, - "node_modules/jest-environment-jsdom/node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "dev": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "map-cache": "^0.2.2" }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/jest-environment-jsdom/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "node": ">= 0.6" } }, - "node_modules/jest-environment-jsdom/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jest-environment-jsdom/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/jest-environment-jsdom/node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" } }, - "node_modules/jest-environment-jsdom/node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "license": "MIT", "dependencies": { - "punycode": "^2.1.1" + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" + "node": ">=10" } }, - "node_modules/jest-environment-jsdom/node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "xml-name-validator": "^3.0.0" + "minipass": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">= 8" } }, - "node_modules/jest-environment-jsdom/node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "BSD-2-Clause", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">=10.4" + "node": ">=8" } }, - "node_modules/jest-environment-jsdom/node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "0.4.24" - } + "license": "ISC" }, - "node_modules/jest-environment-jsdom/node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", "dev": true, "license": "MIT" }, - "node_modules/jest-environment-jsdom/node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", + "deprecated": "This package is no longer supported.", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" } }, - "node_modules/jest-environment-jsdom/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/jest-environment-jsdom/node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "Apache-2.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 10.14.2" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/types": "^26.6.2", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", - "walker": "^1.0.7" - }, "engines": { - "node": ">= 10.14.2" - }, - "optionalDependencies": { - "fsevents": "^2.1.2" + "node": ">= 0.4" } }, - "node_modules/jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^26.6.2", - "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=6.9.0" } }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.4" } }, - "node_modules/jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "pump": "^3.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.2" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.10.0" } }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "assert-plus": "^1.0.0" } }, - "node_modules/jest-message-util/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*" + "is-glob": "^4.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 6" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "node_modules/glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==", + "dev": true, + "license": "BSD" + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" } }, - "node_modules/jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "node_modules/global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", "dev": true, "license": "MIT", + "dependencies": { + "ini": "1.3.7" + }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", - "slash": "^3.0.0" + "type-fest": "^0.20.2" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { - "node": ">= 10.14.2" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-resolve/node_modules/slash": { + "node_modules/globby/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", @@ -16765,4661 +11115,4503 @@ "node": ">=8" } }, - "node_modules/jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.7.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "source-map-support": "^0.5.6", - "throat": "^5.0.0" - }, - "engines": { - "node": ">= 10.14.2" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "slash": "^3.0.0", - "strip-bom": "^4.0.0", - "yargs": "^15.4.1" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=8.6" } }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "license": "ISC" }, - "node_modules/jest-runtime/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.4" + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6.0" } }, - "node_modules/jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", - "chalk": "^4.0.0", - "expect": "^26.6.2", - "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", - "semver": "^7.3.2" - }, - "engines": { - "node": ">= 10.14.2" + "sprintf-js": "~1.0.2" } }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "@types/node": "*", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" }, "engines": { - "node": ">= 10.14.2" + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" } }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "ISC", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" } }, - "node_modules/jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", - "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "leven": "^3.1.0", - "pretty-format": "^26.6.2" + "ajv": "^6.12.3", + "har-schema": "^2.0.0" }, "engines": { - "node": ">= 10.14.2" + "node": ">=6" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4.0" } }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "license": "MIT", - "dependencies": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^26.6.2", - "string-length": "^4.0.1" - }, "engines": { - "node": ">= 10.14.2" + "node": ">=4" } }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "es-define-property": "^1.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "dunder-proto": "^1.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" + "engines": { + "node": ">= 0.4" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", - "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/jsdom": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", - "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssstyle": "^4.1.0", - "data-urls": "^5.0.0", - "decimal.js": "^10.4.3", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.12", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.7.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^5.0.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0", - "ws": "^8.18.0", - "xml-name-validator": "^5.0.0" + "dependencies": { + "has-symbols": "^1.0.3" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "canvas": "^2.11.2" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jsdom/node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "xmlchars": "^2.2.0" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" }, "engines": { - "node": ">=v12.22.7" + "node": ">=0.10.0" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "dev": true, "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "license": "ISC" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "dev": true, "license": "MIT", - "bin": { - "json5": "lib/cli.js" + "dependencies": { + "kind-of": "^3.0.2" }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "dev": true, "license": "MIT", "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=0.6.0" + "node": ">=0.10.0" } }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/jszip/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + }, + "node_modules/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==", "dev": true, "license": "MIT" }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, - "node_modules/karma": { - "version": "6.4.4", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", - "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", "dependencies": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.7.2", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" - }, - "bin": { - "karma": "bin/karma" + "function-bind": "^1.1.2" }, "engines": { - "node": ">= 10" + "node": ">= 0.4" } }, - "node_modules/karma-chrome-launcher": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", - "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, "license": "MIT", - "dependencies": { - "which": "^1.2.1" + "bin": { + "he": "bin/he" } }, - "node_modules/karma-chrome-launcher/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/hex-color-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", + "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==", "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "license": "MIT" + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" } }, - "node_modules/karma-firefox-launcher": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-2.1.3.tgz", - "integrity": "sha512-LMM2bseebLbYjODBOVt7TCPP9OI2vZIXCavIXhkO9m+10Uj5l7u/SKoeRmYx8FYHTVGZSpk6peX+3BMHC1WwNw==", + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", "dev": true, "license": "MIT", "dependencies": { - "is-wsl": "^2.2.0", - "which": "^3.0.0" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/karma-firefox-launcher/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "node_modules/hogan.js": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz", + "integrity": "sha512-RqGs4wavGYJWE07t35JQccByczmNUXQT0E12ZYV1VKYu5UiAU9lsos/yBAcf840+zrUQQxgVduCR5/B8nNtibg==", "dev": true, - "license": "ISC", "dependencies": { - "isexe": "^2.0.0" + "mkdirp": "0.3.0", + "nopt": "1.0.10" }, "bin": { - "node-which": "bin/which.js" - }, + "hulk": "bin/hulk" + } + }, + "node_modules/hogan.js/node_modules/mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha512-OHsdUcVAQ6pOtg5JYWpCBo9W/GySVuwvP9hueRMW7UqshC0tbfzLv8wjySTPm3tfUZ/21CE9E1pJagOA91Pxew==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "license": "MIT/X11", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "*" } }, - "node_modules/karma-jasmine": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.1.0.tgz", - "integrity": "sha512-i/zQLFrfEpRyQoJF9fsCdTMOF5c2dK7C7OmsuKg2D0YSsuZSfQDiLuaiktbuio6F2wiCsZSnSnieIQ0ant/uzQ==", + "node_modules/hogan.js/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "license": "MIT", "dependencies": { - "jasmine-core": "^4.1.0" + "abbrev": "1" }, - "engines": { - "node": ">=12" + "bin": { + "nopt": "bin/nopt.js" }, - "peerDependencies": { - "karma": "^6.0.0" + "engines": { + "node": "*" } }, - "node_modules/karma-jasmine-html-reporter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz", - "integrity": "sha512-sPQE1+nlsn6Hwb5t+HHwyy0A1FNCVKuL1192b+XNauMYWThz2kweiBVW1DqloRpVvZIJkIoHVB7XRpK78n1xbQ==", + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, "license": "MIT", - "peerDependencies": { - "jasmine-core": "^4.0.0 || ^5.0.0", - "karma": "^6.0.0", - "karma-jasmine": "^5.0.0" + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, - "node_modules/karma-jasmine/node_modules/jasmine-core": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", - "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", + "node_modules/hsl-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", + "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A==", "dev": true, "license": "MIT" }, - "node_modules/karma-sourcemap-loader": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/karma-sourcemap-loader/-/karma-sourcemap-loader-0.4.0.tgz", - "integrity": "sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA==", + "node_modules/hsla-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", + "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA==", "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.10" - } + "license": "MIT" }, - "node_modules/karma-webpack": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-4.0.2.tgz", - "integrity": "sha512-970/okAsdUOmiMOCY8sb17A2I8neS25Ad9uhyK3GHgmRSIFJbDcNEFE8dqqUhNe9OHiCC9k3DMrSmtd/0ymP1A==", + "node_modules/html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==", "dev": true, - "license": "MIT", - "dependencies": { - "clone-deep": "^4.0.1", - "loader-utils": "^1.1.0", - "neo-async": "^2.6.1", - "schema-utils": "^1.0.0", - "source-map": "^0.7.3", - "webpack-dev-middleware": "^3.7.0" - }, - "engines": { - "node": ">= 8.9.0" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } + "license": "MIT" }, - "node_modules/karma-webpack/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" }, "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/karma-webpack/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "html-minifier": "cli.js" }, "engines": { - "node": ">=4.0.0" + "node": ">=4" } }, - "node_modules/karma-webpack/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "node_modules/html-minifier/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/html-minifier/node_modules/uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" }, "engines": { - "node": ">= 4" + "node": ">=0.8.0" } }, - "node_modules/karma-webpack/node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "node_modules/html-minifier/node_modules/uglify-js/node_modules/commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT" + }, + "node_modules/html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha512-+Il6N8cCo2wB/Vd3gqy/8TZhTD3QvcVeQLCnZiGkGCH3JP28IgGAY41giccp2W4R3jfyJPAP318FQTa1yU7K7g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 12" + "node": ">=4" } }, - "node_modules/karma/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", "dev": true, - "license": "ISC", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" } }, - "node_modules/karma/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/htmlparser2/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/karma/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "node_modules/htmlparser2/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" }, - "node_modules/karma/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "node_modules/htmlparser2/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, - "license": "ISC" + "license": "BSD-2-Clause" }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, "engines": { - "node": ">=6" + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/last-call-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", - "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "license": "MIT", "dependencies": { - "lodash": "^4.17.5", - "webpack-sources": "^1.1.0" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" } }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "node_modules/http-proxy-middleware": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz", + "integrity": "sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==", "dev": true, "license": "MIT", "dependencies": { - "package-json": "^6.3.0" + "@types/http-proxy": "^1.17.5", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" }, "engines": { - "node": ">=8" + "node": ">=8.0.0" } }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "license": "MIT", "dependencies": { - "readable-stream": "^2.0.5" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" }, "engines": { - "node": ">= 0.6.3" + "node": ">=0.8", + "npm": ">=1.3.7" } }, - "node_modules/lazystream/node_modules/isarray": { + "node_modules/https-browserify": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", "dev": true, "license": "MIT" }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "safe-buffer": "~5.1.0" + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "node_modules/icss-utils/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "license": "ISC" }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/icss-utils/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" + "node": ">=6.0.0" }, - "bin": { - "license-checker": "bin/license-checker" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/license-checker/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" }, - "node_modules/license-checker/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } + "license": "MIT" }, - "node_modules/license-checker/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">= 4" } }, - "node_modules/lie": { + "node_modules/immediate": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==", "dev": true, "license": "MIT" }, - "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "node_modules/import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha512-Ew5AZzJQFqrOV5BTW3EIoHAnoie1LojZLXKcCQ/yTRyVZosBhK1x1ViYjHGf5pAFOq8ZyChZp6m/fSN7pJyZtg==", "dev": true, "license": "MIT", "dependencies": { - "uc.micro": "^1.0.1" + "import-from": "^2.1.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "node_modules/import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha512-0vdnLL2wSGnhlRmzHJAg5JHjt1l2vYhzJ7tNLGbeVg0fse56tpGaH0uzH+r9Slej+BSXXEHvBKDEnVSLLE9/+w==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "resolve-from": "^3.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/load-json-file/node_modules/pify": { + "node_modules/import-from/node_modules/resolve-from": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/load-script": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", - "integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==", + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "node_modules/import-local/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" + "node": ">=8" } }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "node_modules/import-local/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=8.9.0" + "node": ">=8" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/import-local/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "node_modules/import-local/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/lodash.chunk": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", - "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "node_modules/indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==", "dev": true, "license": "MIT" }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "node_modules/internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.10" + } }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", - "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", + "node_modules/ip": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", "dev": true, "license": "MIT" }, - "node_modules/lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/lodash.isnil": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz", - "integrity": "sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==", + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.10" + } }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "node_modules/is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha512-vOx7VprsKyllwjSkLV79NIhpyLfr3jAp7VaTCMXOJHu4m0Ew1CZ2fcjASwmV1jI3BWuWHB013M48eyeldk9gYg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/lodash.isundefined": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", - "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==", + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } }, - "node_modules/lodash.kebabcase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT" }, - "node_modules/lodash.padstart": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", - "integrity": "sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "deprecated": "This package is deprecated. Use https://socket.dev/npm/package/eta instead.", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", "dependencies": { - "lodash._reinterpolate": "^3.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true, "license": "MIT" }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/log4js": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", - "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" + "ci-info": "^2.0.0" }, - "engines": { - "node": ">=8.0" + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-color-stop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", + "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-color-names": "^0.0.4", + "hex-color-regex": "^1.1.0", + "hsl-regex": "^1.0.0", + "hsla-regex": "^1.0.0", + "rgb-regex": "^1.0.1", + "rgba-regex": "^1.0.0" } }, - "node_modules/loglevel": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", - "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, "engines": { - "node": ">= 0.6.0" + "node": ">= 0.4" }, "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/loglevel" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lowercase-keys": { + "node_modules/is-data-descriptor": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", "dependencies": { - "yallist": "^3.0.2" + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=6" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "tmpl": "1.0.5" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" } }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, "license": "MIT", - "dependencies": { - "object-visit": "^1.0.0" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it-anchor": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", - "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", - "dev": true, - "license": "Unlicense", - "peerDependencies": { - "markdown-it": "*" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/markdown-it-chain": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz", - "integrity": "sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, "license": "MIT", "dependencies": { - "webpack-chain": "^4.9.0" + "call-bound": "^1.0.3" }, "engines": { - "node": ">=6.9" + "node": ">= 0.4" }, - "peerDependencies": { - "markdown-it": ">=5.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/markdown-it-chain/node_modules/deepmerge": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", - "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/markdown-it-chain/node_modules/javascript-stringify": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", - "integrity": "sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it-chain/node_modules/webpack-chain": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", - "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", "dev": true, - "license": "MPL-2.0", + "license": "MIT", "dependencies": { - "deepmerge": "^1.5.2", - "javascript-stringify": "^1.6.0" + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/markdown-it-container": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-2.0.0.tgz", - "integrity": "sha512-IxPOaq2LzrGuFGyYq80zaorXReh2ZHGFOB1/Hen429EJL1XkPI3FJTpx9TsJeua+j2qTru4h3W1TiCRdeivMmA==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it-emoji": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", - "integrity": "sha512-QCz3Hkd+r5gDYtS2xsFXmBYrgw6KuWcJZLCEkdfAuwzZbShCmCfta+hwAMq4NX/4xPzkSHduMKgMkkPUJxSXNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it-footnote": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-4.0.0.tgz", - "integrity": "sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it-regex": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/markdown-it-regex/-/markdown-it-regex-0.2.2.tgz", - "integrity": "sha512-Db/QKAwTuDZT0wVNA5WNI2lZOSDyA6xcOax9KxWlsVqGJKw/hd6s8WRycwzvAvjaMy/0EYg0GmrMvIGEiBRwyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it-table-of-contents": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", - "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, "engines": { - "node": ">6.4.0" + "node": ">=0.10.0" } }, - "node_modules/markdown-it/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", "dev": true, "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/markdown-it/node_modules/entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, - "license": "BSD-2-Clause" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/markdown-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", - "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, "license": "MIT", - "dependencies": { - "repeat-string": "^1.0.0" + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/marked": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", - "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==", + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", "dev": true, "license": "MIT", - "bin": { - "marked": "bin/marked" - }, "engines": { - "node": ">= 8.16.2" + "node": ">=8" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=0.12.0" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=6" } }, - "node_modules/memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", "dev": true, "license": "MIT", "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "is-path-inside": "^2.1.0" }, "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" + "node": ">=6" } }, - "node_modules/memory-fs/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/memory-fs/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", "dev": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" } }, - "node_modules/memory-fs/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/memory-fs/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, "engines": { - "node": ">= 0.10.0" + "node": ">=0.10.0" } }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/merge-source-map": { + "node_modules/is-resolvable": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, "license": "MIT", - "dependencies": { - "source-map": "^0.6.1" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true, "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, "license": "MIT", "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": ">=8.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" + "which-typed-array": "^1.1.16" }, - "bin": { - "miller-rabin": "bin/miller-rabin" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true, "license": "MIT" }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, "license": "MIT", - "bin": { - "mime": "cli.js" - }, "engines": { - "node": ">=4.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "dev": true, "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/min-document": { - "version": "2.19.2", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz", - "integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==", + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, "license": "MIT", - "dependencies": { - "dom-walk": "^0.1.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/mini-css-extract-plugin": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz", - "integrity": "sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw==", + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/javascript-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz", + "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", "dev": true, "license": "MIT", "dependencies": { - "loader-utils": "^1.1.0", - "normalize-url": "^2.0.1", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" }, "engines": { - "node": ">= 6.9.0" + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" }, - "peerDependencies": { - "webpack": "^4.4.0" + "engines": { + "node": ">=8" } }, - "node_modules/mini-css-extract-plugin/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "argparse": "^2.0.1" }, "bin": { - "json5": "lib/cli.js" + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/mini-css-extract-plugin/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", "dev": true, "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, "engines": { - "node": ">=4.0.0" + "node": ">=12.0.0" } }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">= 4" + "node": ">=6" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } + "license": "MIT" }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } + "license": "(AFL-2.1 OR BSD-3-Clause)" }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } + "license": "MIT" }, - "node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true, "license": "ISC" }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" + "license": "MIT", + "bin": { + "json5": "lib/cli.js" }, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "universalify": "^2.0.0" }, - "engines": { - "node": ">=8" + "optionalDependencies": { + "graceful-fs": "^4.1.6" } }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" }, "engines": { - "node": ">=8" + "node": ">=0.6.0" } }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" + "json-buffer": "3.0.1" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", "dev": true, "license": "ISC" }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, "engines": { - "node": ">= 18" + "node": ">=0.10.0" } }, - "node_modules/mississippi": { + "node_modules/last-call-webpack-plugin": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", + "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">=4.0.0" + "lodash": "^4.17.5", + "webpack-sources": "^1.1.0" } }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", "dev": true, "license": "MIT", "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "package-json": "^6.3.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/license-checker": { + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", + "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "minimist": "^1.2.6" + "chalk": "^2.4.1", + "debug": "^3.1.0", + "mkdirp": "^0.5.1", + "nopt": "^4.0.1", + "read-installed": "~4.0.3", + "semver": "^5.5.0", + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-satisfies": "^4.0.0", + "treeify": "^1.1.0" }, "bin": { - "mkdirp": "bin/cmd.js" + "license-checker": "bin/license-checker" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "node_modules/license-checker/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", - "engines": { - "node": "*" + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", - "deprecated": "This package is no longer supported.", + "node_modules/license-checker/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", - "dependencies": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" + "bin": { + "semver": "bin/semver" } }, - "node_modules/move-concurrently/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/license-checker/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "uc.micro": "^1.0.1" + } }, - "node_modules/multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, "license": "MIT", "dependencies": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" }, - "bin": { - "multicast-dns": "cli.js" + "engines": { + "node": ">=4" } }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", + "node_modules/load-json-file/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/nan": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.24.0.tgz", - "integrity": "sha512-Vpf9qnVW1RaDkoNKFUvfxqAbtI8ncb8OJlqZ9wwpXzWPEsvsB1nvdUi6oYrHIkQ1Y/tMDnr1h4nczS0VB9Xykg==", + "node_modules/load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=4.3.0 <5.0.0 || >=5.10" } }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, "license": "MIT", "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.9.0" } }, - "node_modules/nanomatch/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nanomatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.chunk": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", + "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.padstart": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz", + "integrity": "sha512-sW73O6S8+Tg66eY56DBk85aQzzUJDtpoXFBgELMd5P/SotAguo+1kYO6RuYgXxA4HJH3LFTFPASX6ET6bjfriw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", "dev": true, - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/nanomatch/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/lodash.template": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", + "deprecated": "This package is deprecated. Use https://socket.dev/npm/package/eta instead.", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "lodash._reinterpolate": "^3.0.0", + "lodash.templatesettings": "^4.0.0" } }, - "node_modules/nanomatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" + "lodash._reinterpolate": "^3.0.0" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true, "license": "MIT" }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true, - "license": "MIT" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", "dev": true, "license": "MIT" }, - "node_modules/no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true, "license": "MIT", - "dependencies": { - "lower-case": "^1.1.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.0.0" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true, "license": "MIT" }, - "node_modules/node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/node-libs-browser/node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "license": "MIT", "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" } }, - "node_modules/node-libs-browser/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "node_modules/node-libs-browser/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/node-libs-browser/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true, "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/node-libs-browser/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-libs-browser/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", + "node_modules/markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" } }, - "node_modules/node-notifier/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/markdown-it-anchor": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", + "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", "dev": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" + "license": "Unlicense", + "peerDependencies": { + "markdown-it": "*" + } + }, + "node_modules/markdown-it-chain": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/markdown-it-chain/-/markdown-it-chain-1.3.0.tgz", + "integrity": "sha512-XClV8I1TKy8L2qsT9iX3qiV+50ZtcInGXI80CA+DP62sMs7hXlyV/RM3hfwy5O3Ad0sJm9xIwQELgANfESo8mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "webpack-chain": "^4.9.0" }, "engines": { - "node": ">=10" + "node": ">=6.9" + }, + "peerDependencies": { + "markdown-it": ">=5.0.0" } }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "node_modules/markdown-it-chain/node_modules/javascript-stringify": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-1.6.0.tgz", + "integrity": "sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ==", "dev": true, "license": "MIT" }, - "node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "node_modules/markdown-it-chain/node_modules/webpack-chain": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-4.12.1.tgz", + "integrity": "sha512-BCfKo2YkDe2ByqkEWe1Rw+zko4LsyS75LVr29C6xIrxAg9JHJ4pl8kaIZ396SUSNp6b4815dRZPSTAS8LlURRQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, - "license": "ISC", + "license": "MPL-2.0", "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" + "deepmerge": "^1.5.2", + "javascript-stringify": "^1.6.0" } }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/markdown-it-container": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-container/-/markdown-it-container-2.0.0.tgz", + "integrity": "sha512-IxPOaq2LzrGuFGyYq80zaorXReh2ZHGFOB1/Hen429EJL1XkPI3FJTpx9TsJeua+j2qTru4h3W1TiCRdeivMmA==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } + "license": "MIT" }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha512-QCz3Hkd+r5gDYtS2xsFXmBYrgw6KuWcJZLCEkdfAuwzZbShCmCfta+hwAMq4NX/4xPzkSHduMKgMkkPUJxSXNg==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } + "license": "MIT" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/markdown-it-footnote": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-4.0.0.tgz", + "integrity": "sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/markdown-it-regex": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/markdown-it-regex/-/markdown-it-regex-0.2.2.tgz", + "integrity": "sha512-Db/QKAwTuDZT0wVNA5WNI2lZOSDyA6xcOax9KxWlsVqGJKw/hd6s8WRycwzvAvjaMy/0EYg0GmrMvIGEiBRwyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdown-it-table-of-contents": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/markdown-it-table-of-contents/-/markdown-it-table-of-contents-0.4.4.tgz", + "integrity": "sha512-TAIHTHPwa9+ltKvKPWulm/beozQU41Ab+FIefRaQV1NRnpzwcV9QOe6wXQS5WLivm5Q/nlo0rl6laGkMDZE7Gw==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">6.4.0" } }, - "node_modules/normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "node_modules/markdown-it/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "license": "MIT", "dependencies": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - }, - "engines": { - "node": ">=4" + "sprintf-js": "~1.0.2" } }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "node_modules/markdown-it/node_modules/entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", "dev": true, - "license": "ISC" + "license": "BSD-2-Clause" }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" + "repeat-string": "^1.0.0" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.9.tgz", + "integrity": "sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==", + "dev": true, + "license": "MIT", "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" + "marked": "bin/marked" }, "engines": { - "node": ">= 4" + "node": ">= 8.16.2" } }, - "node_modules/npm-run-all/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/npm-run-all/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "node_modules/npm-run-all/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true, "license": "MIT" }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "dev": true, "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "errno": "^0.1.3", + "readable-stream": "^2.0.1" }, "engines": { - "node": ">=4.8" + "node": ">=4.3.0 <5.0.0 || >=5.10" } }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true, - "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.10.0" } }, - "node_modules/npm-run-all/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, - "bin": { - "which": "bin/which" + "engines": { + "node": ">=8.6" } }, - "node_modules/npm-run-path": { + "node_modules/miller-rabin": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "bn.js": "^4.0.0", + "brorand": "^1.0.1" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "~1.0.0" + "bin": { + "miller-rabin": "bin/miller-rabin" } }, - "node_modules/num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, "license": "MIT" }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, "engines": { - "node": "*" + "node": ">=4.0.0" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "mime-db": "1.52.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "dev": true, "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/min-document": { + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz", + "integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "dom-walk": "^0.1.0" } }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "node_modules/mini-css-extract-plugin": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.6.0.tgz", + "integrity": "sha512-79q5P7YGI6rdnVyIAV4NXpBQJFWdkzJxCim3Kog4078fM0piAaFlwocqbejdWtLW1cEzCexPrh6EdyFsPgVdAw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" + "loader-utils": "^1.1.0", + "normalize-url": "^2.0.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 6.9.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "webpack": "^4.4.0" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "node_modules/mini-css-extract-plugin/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "node_modules/mini-css-extract-plugin/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "isobject": "^3.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0" } }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 4" } }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.9.tgz", - "integrity": "sha512-mt8YM6XwsTTovI+kdZdHSxoyF2DI59up034orlC9NfweclcWOt7CVascNNLp6U+bjFVCVCIh9PwS76tDM/rH8g==", + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true, - "license": "MIT", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", "dependencies": { - "array.prototype.reduce": "^1.0.8", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "gopd": "^1.2.0", - "safe-array-concat": "^1.1.3" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.4" - }, + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "minipass": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 8" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/on-build-webpack": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/on-build-webpack/-/on-build-webpack-0.1.0.tgz", - "integrity": "sha512-kBBhiDBQP+2wEqUe467fGw4V1aUP93ed7L1eG2TG15M6uOL4IKeW4zIU0yc6MCGmUkPVf883vPkhLEeYubkfng==", + "node_modules/minipass-collect/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ee-first": "1.1.1" + "minipass": "^3.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 8" } }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, "license": "ISC", "dependencies": { - "wrappy": "1" + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "mimic-fn": "^2.1.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, - "license": "MIT", - "bin": { - "opencollective-postinstall": "index.js" - } + "license": "ISC" }, - "node_modules/opn": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", - "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "dev": true, "license": "MIT", "dependencies": { - "is-wsl": "^1.1.0" + "minipass": "^7.1.2" }, "engines": { - "node": ">=4" + "node": ">= 18" } }, - "node_modules/opn/node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "node_modules/mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, "engines": { - "node": ">=4" + "node": ">=4.0.0" } }, - "node_modules/optimize-css-assets-webpack-plugin": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.8.tgz", - "integrity": "sha512-mgFS1JdOtEGzD8l+EuISqL57cKO+We9GcoiQEmdCWRqqck+FGNmYJtx9qfAPzEz+lRrlThWMuGDaRkI/yWNx/Q==", + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "license": "MIT", "dependencies": { - "cssnano": "^4.1.10", - "last-call-webpack-plugin": "^3.0.0" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, - "peerDependencies": { - "webpack": "^4.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "license": "MIT", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "is-plain-object": "^2.0.4" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10.0" } }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "node_modules/move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", "deprecated": "This package is no longer supported.", "dev": true, "license": "ISC", "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/move-concurrently/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" } }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "multicast-dns": "cli.js" } }, - "node_modules/p-cancelable": { + "node_modules/multicast-dns-service-types": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "license": "MIT" }, - "node_modules/p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "node_modules/nan": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.25.0.tgz", + "integrity": "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "optional": true }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, "engines": { - "node": ">=4" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/nanomatch/node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/nanomatch/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, "license": "MIT", "dependencies": { - "aggregate-error": "^3.0.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/p-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", - "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "node_modules/nanomatch/node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", "dev": true, "license": "MIT", "dependencies": { - "retry": "^0.12.0" + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" }, "engines": { - "node": ">=6" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "node_modules/nanomatch/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, "license": "MIT", "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" + "is-plain-object": "^2.0.4" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, - "license": "MIT", - "dependencies": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } + "license": "MIT" }, - "node_modules/parallel-transform/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true, "license": "MIT" }, - "node_modules/parallel-transform/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true, "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "engines": { + "node": ">= 0.6" } }, - "node_modules/parallel-transform/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true, "license": "MIT" }, - "node_modules/parallel-transform/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^2.2.0" - } + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "license": "MIT" }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "dev": true, "license": "MIT", "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" + "lower-case": "^1.1.1" } }, - "node_modules/parse-asn1": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", - "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", "dev": true, - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "pbkdf2": "^3.1.5", - "safe-buffer": "^5.2.1" - }, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { - "node": ">= 0.10" + "node": ">= 6.0.0" } }, - "node_modules/parse-imports-exports": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", - "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "dev": true, "license": "MIT", "dependencies": { - "parse-statements": "1.0.11" + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "node_modules/node-libs-browser/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, "engines": { - "node": ">=4" + "node": ">=0.8.x" } }, - "node_modules/parse-statements": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", - "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "node_modules/node-libs-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, "license": "MIT" }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "license": "ISC", "dependencies": { - "entities": "^6.0.0" + "abbrev": "1", + "osenv": "^0.1.4" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "bin": { + "nopt": "bin/nopt.js" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=0.10.0" } }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "node_modules/normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, "engines": { - "node": ">=8" + "node": ">= 4" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "dev": true, "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4.8" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true, - "license": "(WTFPL OR MIT)" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "MIT" + "license": "ISC", + "bin": { + "semver": "bin/semver" + } }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "shebang-regex": "^1.0.0" }, "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/pbkdf2": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", - "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", "dev": true, "license": "MIT", "dependencies": { - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ripemd160": "^2.0.3", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.12", - "to-buffer": "^1.2.1" + "path-key": "^2.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=4" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", "dev": true, "license": "MIT" }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "dev": true, - "license": "ISC" + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "~1.0.0" + } }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "license": "MIT" }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, + "license": "Apache-2.0", "engines": { - "node": ">=0.10" + "node": "*" } }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "dev": true, "license": "MIT", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "license": "MIT", "dependencies": { - "pinkie": "^2.0.0" + "is-buffer": "^1.1.5" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, "license": "MIT", "dependencies": { - "find-up": "^3.0.0" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "isobject": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/portfinder": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", - "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.9.tgz", + "integrity": "sha512-mt8YM6XwsTTovI+kdZdHSxoyF2DI59up034orlC9NfweclcWOt7CVascNNLp6U+bjFVCVCIh9PwS76tDM/rH8g==", "dev": true, "license": "MIT", "dependencies": { - "async": "^3.2.6", - "debug": "^4.3.6" + "array.prototype.reduce": "^1.0.8", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "gopd": "^1.2.0", + "safe-array-concat": "^1.1.3" }, "engines": { - "node": ">= 10.12" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "dev": true, "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-build-webpack": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/on-build-webpack/-/on-build-webpack-0.1.0.tgz", + "integrity": "sha512-kBBhiDBQP+2wEqUe467fGw4V1aUP93ed7L1eG2TG15M6uOL4IKeW4zIU0yc6MCGmUkPVf883vPkhLEeYubkfng==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "ee-first": "1.1.1" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 0.8" } }, - "node_modules/postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true, "license": "MIT", - "dependencies": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" + "engines": { + "node": ">= 0.8" } }, - "node_modules/postcss-calc/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, - "license": "ISC" + "license": "ISC", + "dependencies": { + "wrappy": "1" + } }, - "node_modules/postcss-calc/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "bin": { + "opencollective-postinstall": "index.js" } }, - "node_modules/postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", + "node_modules/opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "is-wsl": "^1.1.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" } }, - "node_modules/postcss-colormin/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss-colormin/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/optimize-css-assets-webpack-plugin": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.8.tgz", + "integrity": "sha512-mgFS1JdOtEGzD8l+EuISqL57cKO+We9GcoiQEmdCWRqqck+FGNmYJtx9qfAPzEz+lRrlThWMuGDaRkI/yWNx/Q==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" + "cssnano": "^4.1.10", + "last-call-webpack-plugin": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "peerDependencies": { + "webpack": "^4.0.0" } }, - "node_modules/postcss-colormin/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { - "node": ">=6.9.0" + "node": ">= 0.8.0" } }, - "node_modules/postcss-convert-values/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/postcss-convert-values/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=0.10.0" } }, - "node_modules/postcss-convert-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "license": "MIT", - "dependencies": { - "postcss": "^7.0.0" - }, "engines": { - "node": ">=6.9.0" + "node": ">=0.10.0" } }, - "node_modules/postcss-discard-comments/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", "dev": true, - "license": "ISC" + "license": "ISC", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } }, - "node_modules/postcss-discard-comments/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true, "license": "MIT", - "dependencies": { - "postcss": "^7.0.0" - }, "engines": { - "node": ">=6.9.0" + "node": ">=6" } }, - "node_modules/postcss-discard-duplicates/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/postcss-discard-duplicates/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-discard-empty/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss-discard-empty/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "aggregate-error": "^3.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", + "node_modules/p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.0" + "retry": "^0.12.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=6" } }, - "node_modules/postcss-discard-overridden/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss-discard-overridden/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=6" } }, - "node_modules/postcss-load-config": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", - "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", "dev": true, "license": "MIT", "dependencies": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" }, "engines": { - "node": ">= 4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=8" } }, - "node_modules/postcss-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", - "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "dev": true, "license": "MIT", "dependencies": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" - }, - "engines": { - "node": ">= 6" + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" } }, - "node_modules/postcss-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "no-case": "^2.2.0" } }, - "node_modules/postcss-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "callsites": "^3.0.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=6" } }, - "node_modules/postcss-loader/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss-loader/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 0.10" } }, - "node_modules/postcss-loader/node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" + "parse-statements": "1.0.11" } }, - "node_modules/postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, "license": "MIT", "dependencies": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" } }, - "node_modules/postcss-merge-longhand/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/postcss-merge-longhand/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 0.8" } }, - "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", "dev": true, "license": "MIT", - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, "engines": { - "node": ">=6.9.0" + "node": ">=0.10.0" } }, - "node_modules/postcss-merge-rules/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/postcss-merge-rules/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==", "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } + "license": "MIT" }, - "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, "engines": { "node": ">=8" } }, - "node_modules/postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, "engines": { - "node": ">=6.9.0" + "node": ">=0.10.0" } }, - "node_modules/postcss-minify-font-values/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", "dev": true, - "license": "ISC" + "license": "(WTFPL OR MIT)" }, - "node_modules/postcss-minify-font-values/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=8" } }, - "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, "license": "MIT" }, - "node_modules/postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", + "node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=6.9.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/postcss-minify-gradients/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss-minify-gradients/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", + "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", "dev": true, - "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": "20 || >=22" } }, - "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true, "license": "MIT" }, - "node_modules/postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "dev": true, "license": "MIT", "dependencies": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=6.9.0" + "node": ">= 0.10" } }, - "node_modules/postcss-minify-params/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-minify-params/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" + "node": ">=8.6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/postcss-minify-params/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", "dev": true, "license": "MIT", - "dependencies": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=6.9.0" + "node": ">=0.10" } }, - "node_modules/postcss-minify-selectors/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/postcss-minify-selectors/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, "license": "MIT", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=0.10.0" } }, - "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "license": "MIT", "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" + "pinkie": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/postcss-modules-extract-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", - "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "dev": true, - "license": "ISC", - "dependencies": { - "postcss": "^7.0.5" - }, + "license": "MIT", "engines": { "node": ">= 6" } }, - "node_modules/postcss-modules-extract-imports/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss-modules-extract-imports/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "find-up": "^3.0.0" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=6" } }, - "node_modules/postcss-modules-local-by-default": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", - "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0", - "postcss-value-parser": "^3.3.1" + "locate-path": "^3.0.0" }, "engines": { - "node": ">= 6" + "node": ">=6" } }, - "node_modules/postcss-modules-local-by-default/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, - "license": "ISC" + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/postcss-modules-local-by-default/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "p-try": "^2.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=6" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-modules-local-by-default/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-modules-scope": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", - "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "postcss": "^7.0.6", - "postcss-selector-parser": "^6.0.0" + "p-limit": "^2.0.0" }, "engines": { - "node": ">= 6" + "node": ">=6" } }, - "node_modules/postcss-modules-scope/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "node_modules/postcss-modules-scope/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/portfinder": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", + "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "async": "^3.2.6", + "debug": "^4.3.6" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">= 10.12" } }, - "node_modules/postcss-modules-values": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", - "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", "dev": true, - "license": "ISC", - "dependencies": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^7.0.6" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/postcss-modules-values/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/postcss-modules-values/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", + "node_modules/postcss-calc": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", + "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" + "postcss": "^7.0.27", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.0.2" } }, - "node_modules/postcss-normalize-charset/node_modules/picocolors": { + "node_modules/postcss-calc/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-charset/node_modules/postcss": { + "node_modules/postcss-calc/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21437,14 +15629,16 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", + "node_modules/postcss-colormin": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", + "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-util-get-match": "^4.0.0", + "browserslist": "^4.0.0", + "color": "^3.0.0", + "has": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" }, @@ -21452,14 +15646,14 @@ "node": ">=6.9.0" } }, - "node_modules/postcss-normalize-display-values/node_modules/picocolors": { + "node_modules/postcss-colormin/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-display-values/node_modules/postcss": { + "node_modules/postcss-colormin/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21477,22 +15671,20 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": { + "node_modules/postcss-colormin/node_modules/postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", + "node_modules/postcss-convert-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", + "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" }, @@ -21500,14 +15692,14 @@ "node": ">=6.9.0" } }, - "node_modules/postcss-normalize-positions/node_modules/picocolors": { + "node_modules/postcss-convert-values/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-positions/node_modules/postcss": { + "node_modules/postcss-convert-values/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21525,37 +15717,34 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { + "node_modules/postcss-convert-values/node_modules/postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/postcss-normalize-repeat-style": { + "node_modules/postcss-discard-comments": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", + "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss": "^7.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-normalize-repeat-style/node_modules/picocolors": { + "node_modules/postcss-discard-comments/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss": { + "node_modules/postcss-discard-comments/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21573,36 +15762,27 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-normalize-string": { + "node_modules/postcss-discard-duplicates": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", + "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", "dev": true, "license": "MIT", "dependencies": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss": "^7.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-normalize-string/node_modules/picocolors": { + "node_modules/postcss-discard-duplicates/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-string/node_modules/postcss": { + "node_modules/postcss-discard-duplicates/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21620,36 +15800,27 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", + "node_modules/postcss-discard-empty": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", + "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss": "^7.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-normalize-timing-functions/node_modules/picocolors": { + "node_modules/postcss-discard-empty/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss": { + "node_modules/postcss-discard-empty/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21667,36 +15838,27 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-normalize-unicode": { + "node_modules/postcss-discard-overridden": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", + "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss": "^7.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-normalize-unicode/node_modules/picocolors": { + "node_modules/postcss-discard-overridden/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-unicode/node_modules/postcss": { + "node_modules/postcss-discard-overridden/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21714,93 +15876,76 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", + "node_modules/postcss-load-config": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", + "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", "dev": true, "license": "MIT", "dependencies": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">= 4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-url/node_modules/normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "node_modules/postcss-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", + "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", "dev": true, "license": "MIT", + "dependencies": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + }, "engines": { - "node": ">=6" + "node": ">= 6" } }, - "node_modules/postcss-normalize-url/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true, - "license": "ISC" - }, - "node_modules/postcss-normalize-url/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "node_modules/postcss-loader/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "license": "MIT", "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" + "minimist": "^1.2.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/postcss-loader/node_modules/loader-utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", + "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, "engines": { - "node": ">=6.9.0" + "node": ">=4.0.0" } }, - "node_modules/postcss-normalize-whitespace/node_modules/picocolors": { + "node_modules/postcss-loader/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss": { + "node_modules/postcss-loader/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21818,36 +15963,45 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "node_modules/postcss-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } }, - "node_modules/postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", + "node_modules/postcss-merge-longhand": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", + "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", + "css-color-names": "0.0.4", "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" + "postcss-value-parser": "^3.0.0", + "stylehacks": "^4.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-ordered-values/node_modules/picocolors": { + "node_modules/postcss-merge-longhand/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-ordered-values/node_modules/postcss": { + "node_modules/postcss-merge-longhand/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21865,37 +16019,39 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": { + "node_modules/postcss-merge-longhand/node_modules/postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/postcss-reduce-initial": { + "node_modules/postcss-merge-rules": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", + "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", "dev": true, "license": "MIT", "dependencies": { "browserslist": "^4.0.0", "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" + "cssnano-util-same-parent": "^4.0.0", + "postcss": "^7.0.0", + "postcss-selector-parser": "^3.0.0", + "vendors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-reduce-initial/node_modules/picocolors": { + "node_modules/postcss-merge-rules/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-reduce-initial/node_modules/postcss": { + "node_modules/postcss-merge-rules/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21913,15 +16069,28 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-reduce-transforms": { + "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-minify-font-values": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", + "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0" }, @@ -21929,14 +16098,14 @@ "node": ">=6.9.0" } }, - "node_modules/postcss-reduce-transforms/node_modules/picocolors": { + "node_modules/postcss-minify-font-values/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-reduce-transforms/node_modules/postcss": { + "node_modules/postcss-minify-font-values/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21954,34 +16123,37 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": { + "node_modules/postcss-minify-font-values/node_modules/postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/postcss-safe-parser": { + "node_modules/postcss-minify-gradients": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz", - "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", + "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", "dev": true, "license": "MIT", "dependencies": { - "postcss": "^7.0.26" + "cssnano-util-get-arguments": "^4.0.0", + "is-color-stop": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/postcss-safe-parser/node_modules/picocolors": { + "node_modules/postcss-minify-gradients/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-safe-parser/node_modules/postcss": { + "node_modules/postcss-minify-gradients/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -21999,43 +16171,39 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "node_modules/postcss-minify-gradients/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", + "node_modules/postcss-minify-params": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", + "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", "dev": true, "license": "MIT", "dependencies": { + "alphanum-sort": "^1.0.0", + "browserslist": "^4.0.0", + "cssnano-util-get-arguments": "^4.0.0", "postcss": "^7.0.0", "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" + "uniqs": "^2.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-svgo/node_modules/picocolors": { + "node_modules/postcss-minify-params/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-svgo/node_modules/postcss": { + "node_modules/postcss-minify-params/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -22053,36 +16221,37 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-svgo/node_modules/postcss-value-parser": { + "node_modules/postcss-minify-params/node_modules/postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", + "node_modules/postcss-minify-selectors": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", + "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", "dev": true, "license": "MIT", "dependencies": { "alphanum-sort": "^1.0.0", + "has": "^1.0.0", "postcss": "^7.0.0", - "uniqs": "^2.0.0" + "postcss-selector-parser": "^3.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/postcss-unique-selectors/node_modules/picocolors": { + "node_modules/postcss-minify-selectors/node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/postcss-unique-selectors/node_modules/postcss": { + "node_modules/postcss-minify-selectors/node_modules/postcss": { "version": "7.0.39", "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", @@ -22100,2004 +16269,2181 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", + "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", "dev": true, "license": "MIT", - "peer": true, - "bin": { - "prettier": "bin/prettier.cjs" + "dependencies": { + "dot-prop": "^5.2.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": ">=8" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "fast-diff": "^1.1.2" + "postcss": "^7.0.5" }, "engines": { - "node": ">=6.0.0" + "node": ">= 6" } }, - "node_modules/pretty-error": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "node_modules/postcss-modules-extract-imports/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^2.0.4" - } + "license": "ISC" }, - "node_modules/pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "node_modules/postcss-modules-extract-imports/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">= 10" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/pretty-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", - "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "node_modules/postcss-modules-local-by-default": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz", + "integrity": "sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==", "dev": true, "license": "MIT", + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0", + "postcss-value-parser": "^3.3.1" + }, "engines": { - "node": ">=4" + "node": ">= 6" } }, - "node_modules/printable-characters": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", - "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "node_modules/postcss-modules-local-by-default/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "Unlicense" + "license": "ISC" }, - "node_modules/prismjs": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", - "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "node_modules/postcss-modules-local-by-default/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, "engines": { - "node": ">=6" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "node_modules/postcss-modules-local-by-default/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, "engines": { - "node": ">= 0.6.0" + "node": ">= 6" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "node_modules/postcss-modules-scope/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "node_modules/postcss-modules-scope/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, "engines": { - "node": ">=0.4.0" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "node_modules/postcss-modules-values": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz", + "integrity": "sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^7.0.6" + } + }, + "node_modules/postcss-modules-values/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/postcss-modules-values/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">= 6" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/postcss-normalize-charset": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", + "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", "dev": true, "license": "MIT", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "postcss": "^7.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=6.9.0" } }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "license": "MIT" - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "node_modules/postcss-normalize-charset/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, "license": "ISC" }, - "node_modules/psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "node_modules/postcss-normalize-charset/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "punycode": "^2.3.1" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/lupomontero" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/psl/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/postcss-normalize-display-values": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", + "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", "dev": true, "license": "MIT", + "dependencies": { + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": ">=6.9.0" } }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "node_modules/postcss-normalize-display-values/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss-normalize-display-values/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "node_modules/postcss-normalize-display-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "node_modules/postcss-normalize-positions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", + "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", "dev": true, "license": "MIT", "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "cssnano-util-get-arguments": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "node_modules/postcss-normalize-positions/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } + "license": "ISC" }, - "node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "node_modules/postcss-normalize-positions/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "node_modules/postcss-normalize-positions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "node_modules/postcss-normalize-repeat-style": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", + "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", "dev": true, "license": "MIT", "dependencies": { - "escape-goat": "^2.0.0" + "cssnano-util-get-arguments": "^4.0.0", + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "node_modules/postcss-normalize-repeat-style/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } + "license": "ISC" }, - "node_modules/qjobs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "node_modules/postcss-normalize-repeat-style/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.9" - } - }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=0.6" + "node": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "node_modules/postcss-normalize-repeat-style/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-normalize-string": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", + "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", "dev": true, "license": "MIT", "dependencies": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/querystring-es3": { + "node_modules/postcss-normalize-string/node_modules/picocolors": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "engines": { - "node": ">=0.4.x" - } + "license": "ISC" }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "node_modules/postcss-normalize-string/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "node_modules/postcss-normalize-string/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/postcss-normalize-timing-functions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", + "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" + "cssnano-util-get-match": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "node_modules/postcss-normalize-timing-functions/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } + "license": "ISC" }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "node_modules/postcss-normalize-timing-functions/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, "engines": { - "node": ">= 0.6" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "node_modules/postcss-normalize-timing-functions/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-normalize-unicode": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", + "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" + "browserslist": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "node_modules/postcss-normalize-unicode/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } + "license": "ISC" }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "node_modules/postcss-normalize-unicode/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "node_modules/postcss-normalize-unicode/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, - "node_modules/read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", - "deprecated": "This package is no longer supported.", + "node_modules/postcss-normalize-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", + "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" + "is-absolute-url": "^2.0.0", + "normalize-url": "^3.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/read-installed/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/postcss-normalize-url/node_modules/normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "node_modules/postcss-normalize-url/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } + "license": "ISC" }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "node_modules/postcss-normalize-url/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=4" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "node_modules/postcss-normalize-url/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-normalize-whitespace": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", + "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", "dev": true, "license": "MIT", "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6.9.0" } }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/postcss-normalize-whitespace/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss-normalize-whitespace/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=8" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/postcss-normalize-whitespace/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-ordered-values": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", + "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "cssnano-util-get-arguments": "^4.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/postcss-ordered-values/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss-ordered-values/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=6" + "node": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/postcss-ordered-values/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-reduce-initial": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", + "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "browserslist": "^4.0.0", + "caniuse-api": "^3.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/read-pkg-up/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/postcss-reduce-initial/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss-reduce-initial/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=8" + "node": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/read-pkg-up/node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "node_modules/postcss-reduce-transforms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", + "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", "dev": true, "license": "MIT", "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "cssnano-util-get-match": "^4.0.0", + "has": "^1.0.0", + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" } }, - "node_modules/read-pkg-up/node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "node_modules/postcss-reduce-transforms/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } + "license": "ISC" }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/postcss-reduce-transforms/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, - "license": "(MIT OR CC0-1.0)", + "license": "MIT", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, "engines": { - "node": ">=8" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "node_modules/postcss-reduce-transforms/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-safe-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz", + "integrity": "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==", "dev": true, "license": "MIT", "dependencies": { - "pify": "^3.0.0" + "postcss": "^7.0.26" }, "engines": { - "node": ">=4" + "node": ">=6.0.0" } }, - "node_modules/read-pkg/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "node_modules/postcss-safe-parser/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } + "license": "ISC" }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/postcss-safe-parser/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.1.0" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "node_modules/postcss-svgo": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", + "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "postcss": "^7.0.0", + "postcss-value-parser": "^3.0.0", + "svgo": "^1.0.0" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "deprecated": "This functionality has been moved to @npmcli/fs", + "node_modules/postcss-svgo/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } + "license": "ISC" }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/postcss-svgo/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">=8.10.0" + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "node_modules/postcss-svgo/node_modules/postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } + "license": "MIT" }, - "node_modules/reduce": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.3.tgz", - "integrity": "sha512-0Dtt3Bgj34/yKFzE5N9V6/HYyP3gb+E3TLs/hMr/wGgkCIzYa+7G4hNrE/P+en52OJT+pLUgmba9DQF3AB+2LQ==", + "node_modules/postcss-unique-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", + "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", "dev": true, "license": "MIT", "dependencies": { - "object-keys": "^1.1.1" + "alphanum-sort": "^1.0.0", + "postcss": "^7.0.0", + "uniqs": "^2.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" } }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "node_modules/postcss-unique-selectors/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss-unique-selectors/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" + "picocolors": "^0.2.1", + "source-map": "^0.6.1" }, "engines": { - "node": ">= 0.4" + "node": ">=6.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" } }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true, "license": "MIT" }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, "engines": { - "node": ">=4" + "node": ">= 0.8.0" } }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", "dev": true, "license": "MIT", - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=0.10.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/regex-not/node_modules/is-extendable": { + "node_modules/prettier-linter-helpers": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "fast-diff": "^1.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/regexp-to-ast": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.4.0.tgz", - "integrity": "sha512-4qf/7IsIKfSNHQXSwial1IFmfM1Cc/whNBQqRwe0V2stPe7KmN1U0tWQiIx6JiirgSrisjE0eECdNf7Tav1Ntw==", - "license": "MIT" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "node_modules/pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "lodash": "^4.17.20", + "renderkid": "^2.0.4" } }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", "dev": true, "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, "engines": { "node": ">=4" } }, - "node_modules/registry-auth-token": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", - "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "dev": true, "license": "MIT", - "dependencies": { - "rc": "1.2.8" - }, "engines": { - "node": ">=6.0.0" + "node": ">=6" } }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, "license": "MIT", - "dependencies": { - "rc": "^1.2.8" - }, "engines": { - "node": ">=8" + "node": ">= 0.6.0" } }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true, "license": "MIT" }, - "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" + "license": "MIT", + "engines": { + "node": ">=0.4.0" } }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, "engines": { "node": ">= 0.10" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true, "license": "ISC" }, - "node_modules/renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", "dev": true, "license": "MIT", "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" } }, - "node_modules/renderkid/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "node_modules/renderkid/node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/renderkid/node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" } }, - "node_modules/renderkid/node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, "license": "MIT", "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/renderkid/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/renderkid/node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "escape-goat": "^2.0.0" }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" + "engines": { + "node": ">=8" } }, - "node_modules/renderkid/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/renderkid/node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" } }, - "node_modules/renderkid/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", "dev": true, - "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=0.4.x" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } + "license": "MIT" }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "node_modules/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" + "safe-buffer": "^5.1.0" } }, - "node_modules/request/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">= 0.6" } }, - "node_modules/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=0.8" + "node": ">= 0.8" } }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "license": "MIT", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, "bin": { - "uuid": "bin/uuid" + "rc": "cli.js" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "node_modules/read-installed": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", + "integrity": "sha512-O03wg/IYuV/VtnK2h/KXEt9VIbMUFbk3ERG0Iu4FhLZw0EP0T9znqrYDGn6ncbEsXUFaUjiVAWXHzxwt3lhRPQ==", + "deprecated": "This package is no longer supported.", "dev": true, - "license": "ISC" + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "slide": "~1.1.3", + "util-extend": "^1.0.1" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.2" + } }, - "node_modules/requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "node_modules/read-installed/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.5" + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "license": "MIT", "dependencies": { - "resolve-from": "^5.0.0" + "pify": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, "license": "MIT" }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, + "license": "ISC", "dependencies": { - "lowercase-keys": "^1.0.0" + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" } }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">=0.12" + "node": ">=8.10.0" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, - "license": "MIT", + "dependencies": { + "resolve": "^1.1.6" + }, "engines": { - "node": ">= 4" + "node": ">= 0.10" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "node_modules/reduce": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/reduce/-/reduce-1.0.3.tgz", + "integrity": "sha512-0Dtt3Bgj34/yKFzE5N9V6/HYyP3gb+E3TLs/hMr/wGgkCIzYa+7G4hNrE/P+en52OJT+pLUgmba9DQF3AB+2LQ==", "dev": true, "license": "MIT", + "dependencies": { + "object-keys": "^1.1.1" + }, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w==", + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", "dev": true, "license": "MIT" }, - "node_modules/rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==", + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } }, - "node_modules/rimraf": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.2.tgz", - "integrity": "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==", + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "glob": "^13.0.0", - "package-json-from-dist": "^1.0.1" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", - "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "minimatch": "^10.1.1", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, - "node_modules/rimraf/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, "engines": { - "node": "20 || >=22" + "node": ">=0.10.0" } }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "node_modules/regexp-to-ast": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.4.0.tgz", + "integrity": "sha512-4qf/7IsIKfSNHQXSwial1IFmfM1Cc/whNBQqRwe0V2stPe7KmN1U0tWQiIx6JiirgSrisjE0eECdNf7Tav1Ntw==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { - "node": "20 || >=22" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/rimraf/node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=4" } }, - "node_modules/ripemd160": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", - "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", "dev": true, "license": "MIT", "dependencies": { - "hash-base": "^3.1.2", - "inherits": "^2.0.4" + "rc": "1.2.8" }, "engines": { - "node": ">= 0.8" + "node": ">=6.0.0" } }, - "node_modules/ripemd160/node_modules/hash-base": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", - "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.1" + "rc": "^1.2.8" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/ripemd160/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", "dev": true, "license": "MIT" }, - "node_modules/ripemd160/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/ripemd160/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.10" + } }, - "node_modules/ripemd160/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "license": "ISC" + }, + "node_modules/renderkid": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" } }, - "node_modules/ripemd160/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "node_modules/renderkid/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/rrweb-cssom": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", - "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, - "license": "MIT" + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } }, - "node_modules/rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "node_modules/renderkid/node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": "6.* || >= 7.*" + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT", + "license": "BSD-2-Clause" + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "queue-microtask": "^1.2.2" + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, - "license": "ISC", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "aproba": "^1.1.1" + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "node_modules/renderkid/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" + "ansi-regex": "^2.0.0" }, "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10" } }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "ret": "~0.1.10" + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", "dev": true, "license": "MIT", - "dependencies": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "bin": { - "sane": "src/cli.js" - }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=0.10.5" } }, - "node_modules/sane/node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, - "license": "ISC", - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } + "license": "MIT" }, - "node_modules/sane/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sane/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "license": "MIT", "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=4.8" + "node": ">=8" } }, - "node_modules/sane/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/sane/node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/sane/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", "dev": true, "license": "MIT", "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" + "lowercase-keys": "^1.0.0" } }, - "node_modules/sane/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true, "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, "engines": { - "node": ">=6" + "node": ">=0.12" } }, - "node_modules/sane/node_modules/is-descriptor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", - "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, "license": "MIT", - "dependencies": { - "is-accessor-descriptor": "^1.0.1", - "is-data-descriptor": "^1.0.1" - }, "engines": { - "node": ">= 0.4" + "node": ">= 4" } }, - "node_modules/sane/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", - "dependencies": { - "is-plain-object": "^2.0.4" - }, "engines": { + "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/sane/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "node_modules/rgb-regex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", + "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w==", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/rgba-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", + "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.2.tgz", + "integrity": "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "kind-of": "^3.0.2" + "glob": "^13.0.0", + "package-json-from-dist": "^1.0.1" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sane/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "node_modules/rimraf/node_modules/glob": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "is-buffer": "^1.1.5" + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sane/node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "node_modules/rimraf/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sane/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "dev": true, "license": "MIT", "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/sane/node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", "dev": true, "license": "MIT", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/sane/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" + "queue-microtask": "^1.2.2" } }, - "node_modules/sane/node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "node_modules/run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" + "aproba": "^1.1.1" } }, - "node_modules/sane/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, "engines": { - "node": ">=4" + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sane/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "node_modules/sane/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dev": true, "license": "MIT", "dependencies": { - "shebang-regex": "^1.0.0" + "es-errors": "^1.3.0", + "isarray": "^2.0.5" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sane/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "ret": "~0.1.10" } }, - "node_modules/sane/node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sane/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } + "license": "MIT" }, "node_modules/sax": { "version": "1.2.4", @@ -24106,19 +18452,6 @@ "dev": true, "license": "ISC" }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/schema-utils": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", @@ -24193,9 +18526,9 @@ } }, "node_modules/send": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.1.tgz", - "integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "dev": true, "license": "MIT", "dependencies": { @@ -24205,13 +18538,13 @@ "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "2.0.1" + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" @@ -24229,37 +18562,10 @@ }, "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/send/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, "node_modules/send/node_modules/mime": { "version": "1.6.0", @@ -24274,16 +18580,6 @@ "node": ">=4" } }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/serialize-javascript": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", @@ -24295,22 +18591,26 @@ } }, "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", "dev": true, "license": "MIT", "dependencies": { - "accepts": "~1.3.4", + "accepts": "~1.3.8", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" }, "engines": { "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/serve-index/node_modules/debug": { @@ -24334,28 +18634,22 @@ } }, "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "license": "MIT", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" - }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -24363,131 +18657,32 @@ "dev": true, "license": "MIT" }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-static/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/serve-static/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", - "bin": { - "mime": "cli.js" - }, "engines": { - "node": ">=4" + "node": ">= 0.6" } }, - "node_modules/serve-static/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" + "parseurl": "~1.3.3", + "send": "~0.19.1" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serve-static/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -24662,14 +18857,6 @@ "node": ">=4" } }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -24770,13 +18957,6 @@ "dev": true, "license": "MIT" }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, "node_modules/sitemap": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-3.2.2.tgz", @@ -24794,45 +18974,6 @@ "npm": ">=4.0.0" } }, - "node_modules/sitemap/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/sitemap/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/sitemap/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/sitemap/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -24955,144 +19096,24 @@ "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/socket.io": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", - "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.6.0", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" - } - }, - "node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-adapter/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=0.10.0" } }, "node_modules/sockjs": { @@ -25137,6 +19158,16 @@ "ms": "^2.1.1" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/sort-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", @@ -25353,6 +19384,21 @@ "wbuf": "^1.7.3" } }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -25468,16 +19514,16 @@ "license": "MIT" }, "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", + "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=8" } }, "node_modules/stack-utils/node_modules/escape-string-regexp": { @@ -25505,13 +19551,13 @@ } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/std-env": { @@ -25546,46 +19592,6 @@ "readable-stream": "^2.0.2" } }, - "node_modules/stream-browserify/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stream-browserify/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-browserify/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/stream-each": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", @@ -25611,46 +19617,6 @@ "xtend": "^4.0.0" } }, - "node_modules/stream-http/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stream-http/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-http/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/stream-shift": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", @@ -25658,21 +19624,6 @@ "dev": true, "license": "MIT" }, - "node_modules/streamroller": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", - "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -25684,28 +19635,21 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, "node_modules/string-replace-loader": { "version": "2.3.0", @@ -25764,22 +19708,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.padend": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", @@ -25871,28 +19799,14 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/strip-bom-string": { @@ -25915,16 +19829,6 @@ "node": ">=0.10.0" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -26100,30 +20004,16 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -26198,17 +20088,10 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" - }, "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -26232,9 +20115,9 @@ } }, "node_modules/tar": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", - "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", + "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -26248,23 +20131,6 @@ "node": ">=18" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tar/node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -26288,27 +20154,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/terser": { - "version": "5.44.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz", - "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -26474,21 +20323,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -26496,13 +20330,6 @@ "dev": true, "license": "MIT" }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "dev": true, - "license": "MIT" - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -26521,46 +20348,6 @@ "xtend": "~4.0.1" } }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -26594,43 +20381,6 @@ "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", "license": "MIT" }, - "node_modules/tldts": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", - "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^6.1.86" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "6.1.86", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", - "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -26805,49 +20555,27 @@ "license": "MIT" }, "node_modules/tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "tldts": "^6.1.32" + "psl": "^1.1.28", + "punycode": "^2.1.1" }, "engines": { - "node": ">=16" + "node": ">=0.8" } }, "node_modules/tr46": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", - "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", "dev": true, "license": "MIT", "dependencies": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "dev": true, - "license": "MIT/X11", - "engines": { - "node": "*" + "punycode": "^2.1.0" } }, "node_modules/treeify": { @@ -26860,61 +20588,6 @@ "node": ">=0.6" } }, - "node_modules/ts-jest": { - "version": "26.5.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", - "integrity": "sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^26.1.0", - "json5": "2.x", - "lodash": "4.x", - "make-error": "1.x", - "mkdirp": "1.x", - "semver": "7.x", - "yargs-parser": "20.x" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "jest": ">=26 <27", - "typescript": ">=3.8 <5.0" - } - }, - "node_modules/ts-jest/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ts-loader": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.4.0.tgz", @@ -26936,6 +20609,22 @@ "webpack": "*" } }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/ts-loader/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -26953,6 +20642,36 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ts-loader/node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", @@ -26966,6 +20685,19 @@ "node": ">=10" } }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -27073,16 +20805,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -27252,81 +20974,13 @@ "license": "MIT", "dependencies": { "fs-extra": "^9.0.1", - "handlebars": "^4.7.6" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "typedoc": ">=0.17.0" - } - }, - "node_modules/typedoc-plugin-markdown/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typedoc-plugin-markdown/node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/typedoc-plugin-markdown/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/typedoc/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/typedoc/node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" + "handlebars": "^4.7.6" }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "typedoc": ">=0.17.0" } }, "node_modules/typedoc/node_modules/semver": { @@ -27342,16 +20996,6 @@ "node": ">=10" } }, - "node_modules/typedoc/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/typescript": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.8.tgz", @@ -27366,33 +21010,6 @@ "node": ">=4.2.0" } }, - "node_modules/ua-parser-js": { - "version": "0.7.41", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz", - "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], - "license": "MIT", - "bin": { - "ua-parser-js": "script/cli.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -27541,13 +21158,13 @@ } }, "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4.0.0" + "node": ">= 10.0.0" } }, "node_modules/unpipe": { @@ -27626,65 +21243,6 @@ "dev": true, "license": "MIT" }, - "node_modules/unzipper": { - "version": "0.10.14", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.14.tgz", - "integrity": "sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "node_modules/unzipper/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unzipper/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/unzipper/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/unzipper/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/upath": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", @@ -27697,9 +21255,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", - "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -27755,6 +21313,22 @@ "url": "https://github.com/yeoman/update-notifier?sponsor=1" } }, + "node_modules/update-notifier/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/update-notifier/node_modules/chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -27769,6 +21343,49 @@ "node": ">=8" } }, + "node_modules/update-notifier/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/update-notifier/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-notifier/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", @@ -27786,16 +21403,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -27903,6 +21510,29 @@ "node": ">=4" } }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/url/node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -27978,13 +21608,14 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "bin/uuid" } }, "node_modules/v8-compile-cache-lib": { @@ -27994,38 +21625,6 @@ "dev": true, "license": "MIT" }, - "node_modules/v8-to-istanbul": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz", - "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==", - "dev": true, - "license": "ISC", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -28084,6 +21683,13 @@ "extsprintf": "^1.2.0" } }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -28091,16 +21697,6 @@ "dev": true, "license": "MIT" }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/vue": { "version": "2.7.16", "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz", @@ -28201,21 +21797,67 @@ "source-map": "0.5.6" } }, + "node_modules/vue-server-renderer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/vue-server-renderer/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/vue-server-renderer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/vue-server-renderer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue-server-renderer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=8" } }, "node_modules/vue-server-renderer/node_modules/hash-sum": { @@ -28245,6 +21887,19 @@ "node": ">=0.10.0" } }, + "node_modules/vue-server-renderer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/vue-style-loader": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz", @@ -28471,40 +22126,6 @@ "smoothscroll-polyfill": "^0.4.3" } }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", - "dev": true, - "license": "MIT", - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, "node_modules/watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", @@ -28764,14 +22385,6 @@ "node": ">=0.10.0" } }, - "node_modules/watchpack-chokidar2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/watchpack-chokidar2/node_modules/micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", @@ -28813,23 +22426,6 @@ "node": ">=0.10.0" } }, - "node_modules/watchpack-chokidar2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/watchpack-chokidar2/node_modules/readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", @@ -28846,25 +22442,6 @@ "node": ">=0.10" } }, - "node_modules/watchpack-chokidar2/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/watchpack-chokidar2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/watchpack-chokidar2/node_modules/to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", @@ -28891,14 +22468,11 @@ } }, "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } + "license": "BSD-2-Clause" }, "node_modules/webpack": { "version": "4.47.0", @@ -28965,16 +22539,6 @@ "node": ">=8" } }, - "node_modules/webpack-chain/node_modules/deepmerge": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", - "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/webpack-cli": { "version": "4.10.0", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", @@ -29091,13 +22655,6 @@ "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/webpack-dev-middleware/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-dev-middleware/node_modules/memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -29109,39 +22666,6 @@ "readable-stream": "^2.0.1" } }, - "node_modules/webpack-dev-middleware/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/webpack-dev-middleware/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/webpack-dev-middleware/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/webpack-dev-server": { "version": "3.11.3", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz", @@ -29208,19 +22732,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/webpack-dev-server/node_modules/anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -29300,58 +22811,6 @@ "fsevents": "^1.2.7" } }, - "node_modules/webpack-dev-server/node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/webpack-dev-server/node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/cliui/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/webpack-dev-server/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-dev-server/node_modules/define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -29366,13 +22825,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-dev-server/node_modules/fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -29389,19 +22841,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/webpack-dev-server/node_modules/fsevents": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", @@ -29446,16 +22885,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", @@ -29539,16 +22968,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/webpack-dev-server/node_modules/is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -29562,38 +22981,17 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/webpack-dev-server/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "node_modules/webpack-dev-server/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, "node_modules/webpack-dev-server/node_modules/micromatch": { @@ -29635,61 +23033,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webpack-dev-server/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-dev-server/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/webpack-dev-server/node_modules/readdirp": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", @@ -29728,13 +23071,6 @@ "node": ">=4" } }, - "node_modules/webpack-dev-server/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-dev-server/node_modules/schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -29750,54 +23086,6 @@ "node": ">= 4" } }, - "node_modules/webpack-dev-server/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/webpack-dev-server/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/string-width/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/string-width/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/webpack-dev-server/node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -29838,84 +23126,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack-dev-server/node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", - "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-limiter": "~1.0.0" - } - }, - "node_modules/webpack-dev-server/node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/webpack-dev-server/node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, "node_modules/webpack-log": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", @@ -29930,17 +23140,6 @@ "node": ">= 6" } }, - "node_modules/webpack-log/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "license": "MIT", - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/webpack-merge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", @@ -29975,13 +23174,6 @@ "node": ">=0.4.0" } }, - "node_modules/webpack/node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack/node_modules/braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", @@ -30132,23 +23324,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack/node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack/node_modules/json5": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", @@ -30227,22 +23402,6 @@ "node": ">=0.10.0" } }, - "node_modules/webpack/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/webpack/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -30257,13 +23416,6 @@ "rimraf": "bin.js" } }, - "node_modules/webpack/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, "node_modules/webpack/node_modules/schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -30299,16 +23451,6 @@ "figgy-pudding": "^3.5.1" } }, - "node_modules/webpack/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/webpack/node_modules/terser": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", @@ -30382,10 +23524,26 @@ "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=14.21.3" + "node": ">=14.21.3" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/webpackbar/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, - "peerDependencies": { - "webpack": "3 || 4 || 5" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/webpackbar/node_modules/chalk": { @@ -30405,79 +23563,84 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "node_modules/webpackbar/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.8.0" + "node": ">=7.0.0" } }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "node_modules/webpackbar/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "license": "Apache-2.0", + "license": "MIT" + }, + "node_modules/webpackbar/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "node_modules/webpackbar/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { - "iconv-lite": "0.6.3" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.8.0" } }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=0.8.0" } }, "node_modules/whatwg-url": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", - "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", "dev": true, "license": "MIT", "dependencies": { - "tr46": "^5.1.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=18" + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" } }, "node_modules/when": { @@ -30577,9 +23740,9 @@ "license": "ISC" }, "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -30663,25 +23826,42 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -30703,25 +23883,13 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "dependencies": { + "async-limiter": "~1.0.0" } }, "node_modules/xdg-basedir": { @@ -30734,16 +23902,6 @@ "node": ">=8" } }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, "node_modules/xmlbuilder": { "version": "13.0.2", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", @@ -30754,13 +23912,6 @@ "node": ">=6.0" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT" - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -30786,63 +23937,87 @@ "license": "ISC" }, "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", + "cliui": "^5.0.0", + "find-up": "^3.0.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^4.2.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" + "yargs-parser": "^13.1.2" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=6" } }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "license": "MIT" + }, "node_modules/yargs/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "locate-path": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/yargs/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=6" } }, "node_modules/yargs/node_modules/p-limit": { @@ -30862,41 +24037,54 @@ } }, "node_modules/yargs/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/yargs/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" }, "engines": { "node": ">=6" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "node_modules/yargs/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "license": "MIT", "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" } }, "node_modules/yn": { @@ -30928,43 +24116,6 @@ "integrity": "sha512-C1x6lfvBICFTQIMgbt3JqMOno3VOtkWat/xEakLTOurskYIHPmzJrzd1e8BnmtdDVJlGuk5D+FxyCA8MPmkIyA==", "dev": true, "license": "MIT" - }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } } } } diff --git a/package.json b/package.json index ca27ce7fc3..4983c4c18c 100644 --- a/package.json +++ b/package.json @@ -75,28 +75,13 @@ "verify:cjs": "node script/check-file.js commonjs", "verify:publish-package": "npm pack | node script/check-publish-package.js", "verify:typings": "tsc --noEmit", - "test": "npm-run-all lint test:unit test:browser test:compatibility", - "test:unit": "cross-env NODE_ICU_DATA=node_modules/full-icu jest", - "test:watch": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch", - "test:tdd": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --watch adding-sheet", - "test:coverage": "npm run test:unit -- --coverage", - "test:logMemory": "cross-env NODE_ICU_DATA=node_modules/full-icu jest --runInBand --logHeapUsage", - "test:unit.ci": "cross-env NODE_ICU_DATA=node_modules/full-icu node --expose-gc ./node_modules/jest/bin/jest --forceExit", - "test:browser": "cross-env-shell BABEL_ENV=dist env-cmd -f ht.config.js karma start", - "test:browser.debug": "cross-env-shell BABEL_ENV=dist NODE_ENV=debug env-cmd -f ht.config.js karma start", - "test:performance": "npm run benchmark:basic && npm run benchmark:cruds", - "test:compatibility": "bash test/compatibility/test-compatibility.sh", "typedoc:build-api": "cross-env NODE_OPTIONS=--openssl-legacy-provider typedoc --options .typedoc.md.ts", - "benchmark:basic": "npm run tsnode test/performance/run-basic-benchmark.ts", - "benchmark:cruds": "npm run tsnode test/performance/run-cruds-benchmark.ts", - "benchmark:write-to-file": "npm run tsnode test/performance/write-to-file.ts", - "benchmark:compare-benchmarks": "npm run tsnode test/performance/compare-benchmarks.ts", "lint": "eslint . --ext .js,.ts", "lint:fix": "eslint . --ext .js,.ts --fix", "audit": "npm audit --omit=dev", - "clean": "rimraf coverage/ commonjs/ dist/ es/ languages/ lib/ typings/ test-jasmine/", + "clean": "rimraf commonjs/ dist/ es/ languages/ lib/ typings/", "compile": "tsc", - "check:licenses": "license-checker --production --excludePackages=\"hyperformula@3.0.1\" --onlyAllow=\"MIT; Apache-2.0; BSD-3-Clause; BSD-2-Clause; ISC; BSD; Unlicense\"", + "check:licenses": "license-checker --production --excludePackages=\"hyperformula@3.1.1\" --onlyAllow=\"MIT; Apache-2.0; BSD-3-Clause; BSD-2-Clause; ISC; BSD; Unlicense\"", "tsnode": "ts-node --transpile-only -O {\\\"module\\\":\\\"commonjs\\\"}" }, "dependencies": { @@ -118,10 +103,6 @@ "@babel/preset-typescript": "^7.26.0", "@babel/register": "^7.25.9", "@babel/runtime": "^7.26.0", - "@types/exceljs": "^0.5.3", - "@types/jasmine": "^5.1.4", - "@types/jest": "^26.0.24", - "@types/jsdom": "^21.1.7", "@types/node": "^17.0.45", "@types/webpack-env": "^1.18.5", "@typescript-eslint/eslint-plugin": "^5.62.0", @@ -134,24 +115,10 @@ "env-cmd": "^10.1.0", "eslint": "^8.57.1", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-jasmine": "^4.2.2", - "eslint-plugin-jest": "^27.9.0", "eslint-plugin-jsdoc": "^50.5.0", "eslint-plugin-license-header": "^0.6.1", "eslint-plugin-prettier": "^5.2.1", "esm": "^3.2.25", - "exceljs": "^4.4.0", - "full-icu": "^1.5.0", - "jasmine": "^5.4.0", - "jest": "^26.6.3", - "jsdom": "^25.0.1", - "karma": "^6.4.4", - "karma-chrome-launcher": "^3.2.0", - "karma-firefox-launcher": "^2.1.3", - "karma-jasmine": "^5.1.0", - "karma-jasmine-html-reporter": "^2.1.0", - "karma-sourcemap-loader": "^0.4.0", - "karma-webpack": "^4.0.2", "license-checker": "^25.0.1", "markdown-it-footnote": "^4.0.0", "markdown-it-regex": "^0.2.0", @@ -162,7 +129,6 @@ "string-replace-loader": "^2.3.0", "tar": "^7.4.3", "terser-webpack-plugin": "^4.2.3", - "ts-jest": "^26.5.6", "ts-loader": "^8.4.0", "ts-node": "^10.9.2", "typedoc": "^0.19.2", diff --git a/test/compatibility/README.md b/test/compatibility/README.md deleted file mode 100644 index 2bf23dc1dc..0000000000 --- a/test/compatibility/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Compatibility Testing - -This directory contains tools for testing HyperFormula's compatibility with Excel by comparing evaluation results. - -## Overview - -This compatibiloty testing tool performs the following steps for each .xlsx in `test_data/` directory: -1. read both formulas and calculated values from the XLSX file -2. evaluate the formulas using HyperFormula -3. compare the HyperFormula's results against the original values -4. report differences - -## Structure - -- **`test-compatibility.sh`** - Main test runner that processes all Excel files in `test_data/` -- **`compare-evaluation-results.ts`** - Core comparison tool -- **`test_data/`** - Collection of Excel test files covering various features - -## Running - -Run all compatibility tests: -```bash -npm run test:compatibility -``` - -Test a specific Excel file: -```bash -ts-node --transpile-only -O '{"module":"commonjs"}' test/compatibility/compare-evaluation-results.ts test/compatibility/test_data/your-file.xlsx -``` - -## Adding Test Cases - -1. Create the XLSX file with both formulas and calculated values using MS Excel or Google Sheets -2. Put the file into `test_data/` directory diff --git a/test/compatibility/compare-evaluation-results.ts b/test/compatibility/compare-evaluation-results.ts deleted file mode 100644 index 02dc205e9a..0000000000 --- a/test/compatibility/compare-evaluation-results.ts +++ /dev/null @@ -1,275 +0,0 @@ -import { CellValue, Workbook, Worksheet } from 'exceljs' -import { ConfigParams, DetailedCellError, HyperFormula, RawCellContent, SerializedNamedExpression, Sheets } from '../../src' - -const HF_CONFIG: Partial = { - licenseKey: 'gpl-v3', - dateFormats: ['MM/DD/YYYY', 'MM/DD/YY', 'YYYY/MM/DD'], - currencySymbol: ['$', 'USD'], - localeLang: 'en-US', - accentSensitive: true, - useArrayArithmetic: true, - ignoreWhiteSpace: 'any', - evaluateNullToZero: true, - leapYear1900: true, - nullDate: { year: 1899, month: 12, day: 31 }, -} - -const NAMED_EXPRESSIONS: SerializedNamedExpression[] = [ - { name: 'TRUE', expression: '=TRUE()' }, - { name: 'FALSE', expression: '=FALSE()' }, -] - -interface CellDiff { - row: number, - col: number, - hf: RawCellContent, - source: RawCellContent, -} - -interface SheetsDiff { - [sheetName: string]: CellDiff[], -} - -/** - * Utility class for comparing values with proper equality logic - */ -class ValueComparator { - private readonly nullLikeValues: unknown[] = [0, '', false, null, undefined] - - /** - * Creates an instance of ValueComparator. - * @param {number} [epsilon=Number.EPSILON] - The tolerance used for floating point comparisons. - */ - constructor(private epsilon: number = Number.EPSILON) {} - - /** - * Determines if two values are equal - * @param {unknown} rawValA - First value to compare - * @param {unknown} rawValB - Second value to compare - * @returns {boolean} true if values are equal, false otherwise - */ - areEqual(rawValA: unknown, rawValB: unknown): boolean { - const valA = this.normalize(rawValA) - const valB = this.normalize(rawValB) - - // Handle number comparison with potential floating point precision issues - if (typeof valA === 'number' && typeof valB === 'number') { - if (isNaN(valA) && isNaN(valB)) return true - return Math.abs(valA - valB) < this.epsilon - } - - // Handle object comparison (dates, etc.) - if (typeof valA === 'object' && typeof valB === 'object') { - return JSON.stringify(valA) === JSON.stringify(valB) - } - - return valA === valB - } - - /** - * Normalizes values for comparison (converts null-like values to 0, extracts error values) - * @param {unknown} val - Value to normalize - * @returns {unknown} Normalized value - */ - normalize(val: unknown): unknown { - if (val instanceof DetailedCellError) { - // console.error('HF Error:', val.value, val.message) - return val.value - } - - if (this.nullLikeValues.includes(val)) { - return 0 - } - - return val - } -} - -/** - * Main function to read Excel file and process it with HyperFormula - */ -async function run(): Promise { - try { - const valueComparator = new ValueComparator(0.000000001) - const filename = process.argv[2] - - if (!filename) { - console.error('Usage: ts-node read-excel-file.ts ') - process.exit(1) - } - - const [readFormulas, readValues] = await readFormulasAndValuesFromXlsxFile(filename) - // console.error('Read formulas:', readFormulas) - const [hfFormulas, hfValues] = evaluateSheet(readFormulas) - - const diffFormulas = compareSheets(hfFormulas, readFormulas) - const diffValues = compareSheets(hfValues, readValues, valueComparator) - - const hasFormulaDiffs = Object.keys(diffFormulas).length > 0 - const hasValueDiffs = Object.keys(diffValues).length > 0 - - if (hasFormulaDiffs) { - console.log('Diff formulas:', diffFormulas) - } - - if (hasValueDiffs) { - console.log('Diff values:', diffValues) - } - - if (hasFormulaDiffs || hasValueDiffs) { - process.exit(1) - } - - process.exit(0) - } catch (error: unknown) { - console.error('Error:', error) - process.exit(1) - } -} - -/** - * Compares two sheets and returns the differences - */ -function compareSheets(hfCollection: Sheets, sourceCollection: Sheets, comparator?: ValueComparator): SheetsDiff { - const allSheetNames = new Set([...Object.keys(hfCollection), ...Object.keys(sourceCollection)]) - - const allSheetsDiff = Array.from(allSheetNames).reduce((acc, sheetName: string) => { - const sheetDiff = compareSingleSheet(hfCollection[sheetName] || [], sourceCollection[sheetName] || [], comparator) - - if (sheetDiff.length > 0) { - acc[sheetName] = sheetDiff - } - - return acc - }, {}) - - return allSheetsDiff -} - -/** - * Compares two single sheet data arrays and returns the differences - */ -function compareSingleSheet(hfData: RawCellContent[][], sourceData: RawCellContent[][], comparator?: ValueComparator): CellDiff[] { - const compare = comparator ? comparator.areEqual.bind(comparator) : (a: unknown, b: unknown) => a === b - - const maxRows = Math.max(hfData.length, sourceData.length) - const sheetDiff = [] as CellDiff[] - - for (let row = 0; row < maxRows; row++) { - const maxCols = Math.max(hfData[row]?.length ?? 0, sourceData[row]?.length ?? 0) - - for (let col = 0; col < maxCols; col++) { - const hfCell = hfData[row]?.[col] ?? null - const sourceCell = sourceData[row]?.[col] ?? null - - if (!compare(hfCell, sourceCell)) { - sheetDiff.push({ - row, - col, - hf: hfCell, - source: sourceCell - }) - } - } - } - - return sheetDiff -} - -/** - * Evaluates formulas using HyperFormula and returns computed values - */ -function evaluateSheet(formulas: Sheets): [Sheets, Sheets] { - const hf = HyperFormula.buildFromSheets(formulas, HF_CONFIG, NAMED_EXPRESSIONS) - return [hf.getAllSheetsSerialized() as Sheets, hf.getAllSheetsValues() as Sheets] -} - -/** - * Clears formulas from _xlfn. prefix - */ -function clearFormulas(formulas: Sheets): Sheets { - return Object.entries(formulas).reduce((acc, [sheetName, sheet]) => { - acc[sheetName] = sheet.map((row) => row.map((cell) => typeof cell === 'string' ? cell.replace('_xlfn.', '') : cell)) - return acc - }, {}) -} - -/** - * Reads formulas and values from an Excel file - */ -async function readFormulasAndValuesFromXlsxFile(filename: string): Promise<[Sheets, Sheets]> { - const workbook = await readXlsxWorkbookFromFile(filename) - const [formulas, values] = convertXlsxWorkbookToFormulasAndValuesArrays(workbook) - const cleanFormulas = clearFormulas(formulas) - return [cleanFormulas, values] -} - -/** - * Reads an Excel workbook from file - */ -async function readXlsxWorkbookFromFile(filename: string): Promise { - const workbook = new Workbook() - await workbook.xlsx.readFile(filename) - return workbook -} - -/** - * Converts Excel workbook to JavaScript arrays format - */ -function convertXlsxWorkbookToFormulasAndValuesArrays(workbook: Workbook): [Sheets, Sheets] { - const workbookData: Sheets = {} - const readValues: Sheets = {} - - workbook.eachSheet((worksheet: Worksheet) => { - const sheetData: RawCellContent[][] = [] - const sheetReadValues: RawCellContent[][] = [] - - const dimensions = worksheet.dimensions - if (!dimensions) { - workbookData[worksheet.name] = sheetData - readValues[worksheet.name] = sheetReadValues - return - } - - for (let rowNum = dimensions.top; rowNum <= dimensions.bottom; rowNum++) { - const rowData: RawCellContent[] = [] - const rowReadValues: RawCellContent[] = [] - - for (let colNum = dimensions.left; colNum <= dimensions.right; colNum++) { - const cell = worksheet.getCell(rowNum, colNum) - - const cellData = cell.formula ? `=${cell.formula}` : cell.value as RawCellContent - const cellValue = readCellValue(cell.value) - - rowData.push(cellData) - rowReadValues.push(cellValue) - } - - sheetData.push(rowData) - sheetReadValues.push(rowReadValues) - } - - workbookData[worksheet.name] = sheetData - readValues[worksheet.name] = sheetReadValues - }) - - return [workbookData, readValues] -} - -/** - * Extracts the actual cell value from an Excel cell value object - * @param {CellValue} cellValueObject - The Excel cell value object to extract from - * @returns {RawCellContent} The extracted cell value - */ -function readCellValue(cellValueObject: CellValue): RawCellContent { - if (!cellValueObject) { - return null - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line - return cellValueObject.result?.error ?? cellValueObject.result ?? (cellValueObject.formula != null ? 0 : cellValueObject) -} - -void run() diff --git a/test/compatibility/test-compatibility.sh b/test/compatibility/test-compatibility.sh deleted file mode 100755 index 81e273da14..0000000000 --- a/test/compatibility/test-compatibility.sh +++ /dev/null @@ -1,13 +0,0 @@ -for file in test/compatibility/test_data/*.xlsx; do - [ ! -f "$file" ] && continue - filename=$(basename "$file") - [[ "$filename" =~ ^~ ]] && continue - echo -e "\033[34mProcessing: $filename\033[0m" - ts-node --transpile-only -O {\"module\":\"commonjs\"} test/compatibility/compare-evaluation-results.ts "$file" - if [ $? -ne 0 ]; then - exit 1 - fi - echo -e "\033[34mDone: $filename\033[0m" -done - -exit 0 diff --git a/test/compatibility/test_data/basic-arithmetic.xlsx b/test/compatibility/test_data/basic-arithmetic.xlsx deleted file mode 100644 index f6d1aece03e2641b471e5815d133c8fac1b78da5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10253 zcmeHNWm_EE(j6?gYY4$11lJ%TI0PSDgF|q4cXt8=mq2jW5MUsdR_&^-AOi=F2Y3QN0ssIMfGkEUTT2)K01E*Czy%<|YKz+1 zIGNZu>8ZHenKLNaLP+Hc z2JP6iY^3DWN5o8WpLm`vENr|t5-BPZ+5fEg?DnzkiwkY7j!_L0{NzZo)w?K-Cu)43 z4@-<8gFAOwCPcxi9XzNs3ve}aXEzo#i=ORKHB8B6F=K*uF*P9)`fL0e^TqGX#PVmV z)^+>pHDKDFM<0E0dKD1uZpAh0bb^#Lo09V8aQD=o+D|xn7}LL8y+7zuLIyiL(YE|% zD}n4e%784JhGi^w&^Nb2(dN^}Z)}hxY23O1D+&=WY;=R;%(ZOhGQkXO!X0rwIvrJW zOoC^JyU5-Q>|)Tt}a~922`8w*1$fyJB0yZ|?cX7{|VT5NzvON1zDS zr;v#_7p~j>_=3lETv5+9I)&%U{7a@2EKv7)e1roi{E4IWs;pFJ&=FZE1yP|K)pIbh za%5rtdHx?a|BDIvAAh|pK@Rv2Zr+9VT}~~8PoTv}u4OTQH5%Ji>LNlg3@tHv5-RwqWr{Y(-<@Fvw?t4B_A+3>0YW=cf)uso!y zkvr%6htYK3ndE{!bipuQ*@N*^{60rR)42+-J}ZjzYhqPpGhXv5!z>3rN_RbDtM*f| z^fugkFDChnJ|#*{oGbRxx4kqu=e}BXoIeIL-MhGvJ4^eH`vW4$ik6{r^;eP%QY(mt zzySaoP+h}>&WxKCi>s}JrJ=2@zk9-IZR3=i}}C+LIQw zV{%HgyOLbIwx{*N{KG^9HzQb2qtG|?{<`-%B(e~H2S^Oy)X5=KY7h|7QL9RGF>NtH z*O-1csnVgu|EU5$YFp=9N*RN(;XzJXax_TvxceoMS1U6I!D(5gCY39BfT{}YeFfcu zjaX@|@~Q=W*3ERE+Y)S7NtyIDyWe-M%xl6}bV4Up;aP1%OKliEL?8H0{g@a2d%Hzn zhu|SsT3Ilh^YH=^+4^FAp?FrYj&{Te!SJ5Us_2+yL8nq`BQS&Ra8y@~V@Q&g;0VnA zTk16L)%V|PPn|WZn=_rb<{M_})RIb^%0Fewo+#DugLO1c&~K|KZeD#KL@9&!Y)2i& zZ~$RzjZD{7ZsG*-cOZTZA4VqS7bY^GNi{1nc3hSOuL)GFOf4ReRP7)j23w+Dxay%i ziAJ~y&@jkP1*$KhCk0PO(u2nuF#_HK?;}1{zSBJod!O@OrKL``sAr!cf?6y_;QMW+ z-Jbo&JH)+lSrd%sl8}eT43bsmJH;$+C9~s4N>C8a(zq!dQ6J^X@27q4(UT7w+zdVnpHAD47Yx!D0Ot7Dr9L zG=8h+7oeJxYCum{{UohZs3E~_rBvcj^ZftWI=CP{(RZ81bn90d5~XM!LUMr{iTaKu{IhDhE)FTe zJ~Ut|0t_AgdbA8#tIm^xf;COt9MkUihRsqLVhts+9)eeoy-d7L{(>MkyukpJCOmRa zHyx%~zE97QEC{iVy@9W4T9JT$pOO+LtNQSsDQ;?nJTJsup!vaHjmUP`S8_a)-IB-8 z$v<3lkn5|uk7217z2|dT)wFDVuz!|&c_&_W0`k34k7>m6?v{6whsZl+=;<+4%Ad8$ zCSzXi6_2c`;)NF8hDM5C&9Gk!korGx<(kobAx2F7q)1!q3nk=VDVu+(B@9}0v7(7z20sLjf$Z766+-Oak13^Cr~CNX zCGyA`B5HeYLM)Z|`rG4dYS<(@E=j|i7kpjIuc*n0P4SJTPy)(aOpGiMAl-w*RAKFA zGFF*12yh6qJ2UFd>K5@Eh5Bg%VMT_4u$_yxpV8(OLMiOu%<&XwK;n${Ea&nB4CNd? z6kv{za*+#8;Dsvr3nn&_N94wiJX$uFSa801eLohzg-XDF4DLY?^9RwY9c#ac$KEu# z9ZtI-85Q|(t1<9nIGL!1>nSKh@QG*_Zf`OECXZ%NlOC>wQE4{XE0+M?`ebH@MhiML z5Bina-l5T2HrvNJXeW&vu}#eNN1mQiLPD{8bJDOtaoauaBF!sdLO_q zECNB9cNg4@;vMtfwt4?#*Zwn?nqzFX%kZMUKlcP}xdutd%ZYavXJUPaOlT7gNoPNG?STbZYkd%4|_Xri4k20=E_ z%5CjXVw=*qlE#MYzNzHKnbU1el)-J;rR;KpJSa6zq))c^QxSn__|;&7 zvzG&HUCsr7Xp<{WvCL6Eux_t}%lWmh8Z7%eLDqhFV;hB;Rf8g%L z$q&v$Dhc63)ZMyR7alnCY47rc`sKA)x>+&eVG3}->7j#;kDCg>dZa2bG9mYLF z211$U+4=6EZ_1?h#zn1CDAL#u1o~tIW#IUOn6U9Gn9%TPL9%x! z7@BO~a0kAltRNN;%~kkjQwx!9Vnp zaCgB$7(D+;!SMUwWaX-Sql&_|8W95en^cb;1w4wp zg@hdi9$_NNed5HEB5(3c>^1c; znhg$v>k43(koFKTUu1G2k}7WQv<-xedx9pLr8aV#F8Ix03`Vuv&|>s61GK1RfBNxT zmT!gAK-S18pYe_MzJiL|N>|JYzxuhX6@Hroxv}7S-E1}2!O|&}lP1n78Ur5@)48Hn zSj3kRI{MU%kZ=(EM>8(fb$0{t_-fWYbG9CC)fyyuVP^vCkODDTwadNSMaDKc27yZ1 z`07EYORQciqOzx}ly;l_%kD|xoD$?N{@Bf$zSDlW<&eR{DNZa1=_d?O6KGF&RJqY{ zXrMjKJOe?((PNO}%CXzLWO9UB7O#XC@37&kcZ+*_{>-+}74m0&qbJ0~&v^F_y>;pu zM_oXkC2&1x_ys$NkyB(k*_2Qn2fXAaP%;e4%VxMChK#Ia%XA8*IgI^Em7Z9Vu-(}?TjbcrBS5BZ+$??79 zyS4i$?aJewLKYL&$gZw3PBl$L!e*WsvG>gZ(ON-NiM2-Hw87raZ133wXkJf>Z?x}W z^%n8p1g&`~DGNN8W0W2pVo>Xol4Gb=We0PpE71+ej`~&0oS?RUDv(Bzx~8GIZerDy zurQRizz#Dl%a2RW)`Q*HU6|YbxI<_{XqsP;Jo{7J|C%FQ=+_B#{<$3APsZ$s>R6dKZ*9@_OZ-~|_QLu0~PlFp{2RAPwkh@Fs9GXowB z%Fd*WKdkwfjQ_F+UBnYJzb8$bv26NOa*tvB4iaf=5fQBqLJ5YhEF6=NHxJvby}jJA zj+Y-wQ*u!$skfwNP>-%iDf^>F&1()kfV3OZ3!+ME#xYNUk~7-4d)^L^jo71gIQ;k& z@;Klo%#laD(w=ZVy(w$d*7K|ccpq&$Y$Jq5L(NQ7FJuoRHFWPb&1g0`{=`+HNdYa! z-Kd;!wY{YUIx@B|a*3009JC{K7KTzp2Y38nq^4vzS}?+U9n9_2(?R4WB~n8T`m5ai z>+R9fbc2=QdBESiAz|w>5O~?sDE5EREX=r9Rvoam2jNGwAGirVwI# zuw_vZ`MgCTR_3Dk^&a}8KbqW?`aV2NHLlzzdT3Y#ztnxWE>+j_JwIXb zy?P+iEZSC~Q}6lD<(`G@80!9J<*d(NWVrBCk6&cr-ir}p_ZcU>q=IkXWodC3^YBcH#?uKD_4$A;aecF^y zRO(+5um|sh!ki%O>IwMny;l6mzax&yfu2VL&w5&vPS({rwbNG)p?)tE(jd-(t=yNH+yF#6Nv?ui_xrXf9B`ZX_@|pIOkhX-b=@fxqDcM+}_fsVh+l zv1vFF9<~)-s?teQ+Yj+eZbc3sH+~hK7AR)PaYc;t)$zhd!-<4(UhBR`^>qQjLc6lv zlRKdCyke%vG%AM*k?ZE&?Muh=p5}R8$kfDbRQ~`rpuAfL=*l_M8e5pnj9SlqTqoYa zLxakY9`qyW<*_lmZKu0a^6ilzz8&|ubD>?aI56F?mKcS&{37(YUY>Hs0ZwKhHGpOp zXW9)ZazvCP!=)ABEP9Pyp298P=d!~JIh2KirUw7%LsHf|ATAS%POp zX<&{&Fdf}QrgzcWTH)(p_EWU4mK}RakSa*aA;_n4I+@|3SH9X@%Us+x{mANO&E*=W z)R3@V!=&lfW8}~(;W>PXW4haAYnxbk%Fw5Rr;u%f%(_#>^m)%RB#l+-PJdgBkwMc1uN$<4UMzWRb;j3+?~xZ%$JyWD_cSUC=3wHn^gmA9?k`L)DDW*A~fTV49r@dmoT*? z&63pG1j|{DiEHav%TGF&+q|E~7|fc_H!ynnWxk%Wt{)*}ocHz6umj6xDnpX`yj`$b zfJ^JjO|-5z)~hG@ZA(O|-|N5XnR9#8OIMB+A>>J{V&1Op2m!_I!F?bvqE2%x?VT0D zlpmS47mUl?MvaaR`lEm~zSB;YZDvmCRlXTl&6>%=)`S4&!oabV$dfhe!G!kVx zI%>CnUUP=L{ac~mmoSFuffl$+p8x>p{}6gdCwD6o$DgaWeANY;1y(d~vMOJ!v!k1F z9vRpL@rg+x{|X{7#%!tKV7P(~nv{Gd`t7Bn%R0|)mGhDeqvGZm1!gz3diko^+j;}( z0-hEm)=xDGG#}FOe7y%+pGx%LXyQ~*%l*hA_Db@;iz8~@IkT5376(wsMKn%Nqpomw zC!-iLtH{x0s7Rw48kBN_in(Y$+Y1NWDq_ic3#W9w=@7xQg~1jR1(OP1tEZB*lOok{w&s8I1*(<9&!Y%_36b_uQV zFDZhn$;3>X8gDWsarGviJD#jD7AMv{!7qs?=z{-L0Uv2vtZRG}lTm#+fOGo%5D8Hx z=$`QXSEE`Dp8L4!yQc2kwBNyHjk z6D7&VxITlqjq_)rf)e}HZ>uUa9x)>4E!qVmv)Y0uv7#k)PVYsjrd4*9lm+VE_CD2! zk+xS0qoCO&e%X!5oFXbiYL@HV`NiafTO2S{^CpSQu0-pypg91uQOH?FD?VhQaE-OQ z@Z40ZMnWubhOj}oAyD#%xi@4Iv+xLGe%=#~2~}^>EP0)*aS(VqWlic{tIvB%`;qfv z`-j6;_lNW?i=@#&x-ZwfX^f9->R*MCL_$9Vud#ZcQOt=(#JLD^u=*!Rkm@AS4)+w!pNp#X`YA? zLm2#mAoUtq(lPLneeUnOI-LGX@+i=xmk8?gc>i>GGXn<`V`V1?a~soNe(x0jv*m^* z29dlA+SE2W6pPr*lHhk?iqj=>>;?Kjmx$FMAHqRN9X~iOeX57NC zc}V*KHuECd-kL&i`I0+U2`kVt=Mn?;I+(g~>s(d7i_-l$evJ`nRwCt6F2ej3j1HwK z8Ka#?h}swy7V&qixr^`2gQSTF8~I=XK6y{b=dckkiL!?v_7}?A@21DHl-l0er0+~#MzFdkQw4`Ri7vg(Qp0T12U>{V2h!n^{{xj1Hl_u4wXslp9Ruf6`&slvM+KHhzK#)6Up!^oIh=KR&;sA4FK31acVG3K z<+&nwHw%3{d0=iVXsqGNG_4N6M5rHRZ?z+}+JAz3v9alOcfvLjsJXuHwPlc&X)dzA z$bNPgXYxXz3sz-2c^IJ>u9`W^U*qw1liNqf9U(d=rg4=(7>x8Ch6;&T_>CdFFjWz* z1Qw^rIa)liFeP1(bl1xVX9sJ^%rIFo8l`X^)S^Jj556jtN$ufN;eBF1Z`h{8CH}3nb^WV|@_Qq3Pn0qr2%R=tsLNqP3$DhtMhXtLc8)AY zwhksg=MCCU{9m0F>Q7M#a!}sk1zk!mQk)3b`_NgGQzrqO{fmOcu){K|^%m&Dt>>7{ zV>`Tgh~&pZa%%L=M_WcYfbu)HUrz*t(nTWB#D&B7v1Cs~tk}<5w62slpUNNAblVvtyjshhUsynHb7E-I}vu?FoWaMd3bacd~5jiayf zpjFzVCp%cYwDAWKhwX-KS_ze8R`3B#iRg=jH3IXB{}K)Yx7)#T=dpC>cv-e5-J$IT0ydLeg`9$dkUYsI<a2L4r`SM0{%%t}>PM)S|CPKQx|&FFP%nJ;i@g8gg$8zZ z|8qj9_xifI02hLY-MRfaGLE~fGYM!7ZAVP)|LGr)$i z$vKz#XfhUEfloz87?}(nvc`dxT@H#7u&v1T=eN@Q5K?Br$N(ZQbY{1*E^MjAy-1+N z2a&EWg5o}cEc!9_-lRlhtph)TrbEX<ocC%$z?o_vq4JyV3I@{}2rO z=(rwlu%2nx0Jp;FIKnN!3%u#{eEt>bA>~=&Zu)uU8Hwu}DbdP|yROOt0nYR_qWr!9 z{-n{eu|r`0SA@3S8=X^EBc8yId(-D9E{eJzuk}p1Xap;?{_tWLSSF}c|NYjff4#MT zUH@hym4eKl4g7gu$G?C-ulZ1F{Kqbj-+{mPy8nRoLmBs5=lgf?pSx~hze^_cq`}dFdOCRQUE5FzG{;-mR^S9N$-wph}ZurAMIPot7f2<;YhyI>{ z{Q>oO{txKy`PlCke$PYxu+TvI%fg?slHbvPmg7IL0Kg#`0Pq)a{vH13IQpM(M`*G1 c-|&A%RRtLYsBiq-K!geaLG_=P=I5vX1J`>Aq5uE@ diff --git a/test/compatibility/test_data/logical-conditions.xlsx b/test/compatibility/test_data/logical-conditions.xlsx deleted file mode 100644 index 0c12788a4414b55186121f686f08b82803c69fa5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11669 zcmeIYbyrD{cY2y?+fDZch})dqL>(W&KVRawdF2 z(i2=dxm?b7%gfs)hQdWm7%LFpCu=d2bDYaG2VTOm~L@+2P zp^#xM{T5S*%f(3Qo`3LfX9Hskjd>X*J=;lFdQg7)f+E zg3M~cv*HARJb@ugXYr_4Y>g4T5lQ7}a$!wsK^k|F!-P zoBxLa`Io<57AL3hFKj-A4BpPI#vlvJxC%+O5UKe1Nv$B&M}8%Jx7tC0hpd7d04Cwv z=JPbXyviGSFi3Q>#ab4Qiq1pQ;94G>{9x}4MNRIIByL}}*^A;bcRhELDk1Go>CzTW zUHYvkM`mc9M11C4v>JJW{v$37T0UMdCSR(*X1|=qn!#NK$egh9ad~i6BgdD6_=$Ai zg`|R?2m+y8vPaXY7=w-mrr#^P2Cay$?{QU?&A7~~46+=!iQRRLtU516(>u_fz3AjK z29=0eQSX>1BnHU7T>EO)v7V1)y7zLx^pp;s4FSUmiq_uT)qjJ;LfRTM3=9A`e)DTc zZ<2AdVsN!}ur#o>wfyD8%2cgwzj7kK_)I@T^}1T5Hv*_NAfT6|tyS~CyPPWT`Y9`d zIQFv^mpq?xkP}&R6slHuelQr=-aKbvnMk>0SZf-Zb1`i-MmQ>KDk=`l zcN5j7!5(V?GHHAq>|GRNqkHEaf*h*Mc;}&QLc6J1#NE<^)DdKzyw?w?+) zFtK3Vcj7WVXSS>}qp4alT_5J+kd+*_o5Sx3aWMTig52;&aRc* zqcpwHAcJ-_!@c<2>$i|gK0*sPfQa0WrK zCLr3*94eTa3?+&Z>)g=zeAhH#?GEl^Bx(L>AI_(lb8sswDdUj29*S&@JqC;O_A>*2 z+IKubq0GqcBER21eR<6w4;2Rgs%V=xx$!FI0Mpl;KcUEtEZKf~1gHA$FlR_q5MPIa z{_`g!w17nuqr3)d-1bCn@eFk;c|#t1!wWDVicO6D(uhGNEX4Z*cF7I1!!VnH_rQSm z(RH)dt>*#7ONE|qw;~W_Cmk(u*3BHxMfnYF4CxuR!mAg2&{9^=T5&PGCt@4wIA zEP$}+DPt3HT`5^k?o6!sK{V7%4(c5IZE#4j_q;kn4aX@U4N@XoZ{{Pu6%7Lq*C=5x z>ORW53G&581l~rxo*S>3GpiBSFU&tyQb*(6cZwd0IK<9;SCT~pz_)26t7(g3WIzxA z3>6Ss5_Mog$Dp9?r$gdVSo(03OH@(_>31=TgGHO9#k;bSs1uo2k!7&H&qK?@B0Vz^ z!}#19Z0A*ovneO#P}?4+iwi$RP9efYcfDV)D)DTI9>OyBGuATqv2}InD&?=*G8hO> zW|T8cKYn25S@msDAAQjr?}(Q8;wwjq3tQ1IRA81cbVcw6%KwIK98|&)_#2=F-k^&M zfChPk?Z4dHU%~qyR|oPIhQ6Kszx|ZOjac+D!i(Joy#!3P+cSGB2HTrVDWzDa`}o-< zaLO7$X?gFQS}Ji5b;j7#FiCdb;(u;g_H`}4BPGB!#W0eB1(vxO8(Kn~_Kl2@gm#+A zSY?tyfI%$oEqrYGXc45){_W&yXId1oC_BcF zV`(>d6Tci(_N!T@PIPDn%kRrWk1H~9SoEm{mx@h8trP=W8Eh;Be(TQ3n+t;qa+QmJAf7BsWjn#!zSO7qr6ac_}JMnMR?`URh?BvMs$Hw%_2V}&{ zMW-_&2cITB5X7AJrc{xBiBZJ}ZEh@Cj;=Kf*6Zt^b!k_*?rG#tkjYqo)BtgRZ}@&(YJ>OGqCyr5f-8VzVq_v4Q^L@-0^$q= zmHT7N{3Czi>}O0?SF{WV9duN8@HEz@;w;Dt@A$B&BGt0V>_iC23l(x7w~$=0T{>y#Ofy{PoS_&$n$ zSC2%TOIK-4Sj!CaC-9-G>C5LkoH0r)j_KzoBz<*ZI=me_f7_xvL%Qn1cQif$astpY zwpE+otlE>Eg)ihAYvPyi7nu^HQ&KOnoa;OHe zk}3<8g_Fal1UpFaR$DmFye?s31EJ9MNwJ@rm`pg(+x4i0^WMQhl49xL>p@6kwfm;@lWRxuwmmU)Ng-kr`)p0!=9kDb#DS|2i{Zyg1=Up#yQ zqU~#1nV^0h_5I_X|5)-gt(BMG95)TV@4ldA+Tu73S!#7=pdlitgm9&!uFZ-bp(D`` ztB~%F4sEHVeAShV({^+*8kza8bNmw(o=E~^QcR!2-Mo_W11Ul+#$#Ehes{E$CT(8(OHAaqVjoUcCMdXcryMDaFx5CNF~_65?Qvt&nPkAnNZSG3^WOY;D0W=ecnji}jqv z^#`h(WVmj4>1bEm78!ub^}x>J0M5ux8E)w3BCU{w2SVb$V6gV1`(Y}}*3xA_)ybNA zkEb@OG;zwe`L=IzVr4uQJU0YVNkGf7nPV8sB%Xc(@Nx?me>JQrZu`utkrM+t&4YkY zOnSU-0jMWf;CTn)C?Dhu3>!fWP#Qi z9FrfXUl=4jg=WY1@ROuBywK0jG{dj>p$Y+zlbz~A8hqUvCFKeRi54XGR=G>Tk4>hF z8yNa!XUieyPaf{*?mu2|&I7&jgy`wsU{DYtK;&(0alqtYY&;}vQ>pvqR^u{R83>EmxeJ`pyT0@}8?b|li{pu`b<5j_9-j^tyc?(< z>d^i1HPQU$k_wSgf7x#CEttN2-02?0E=u?(9gl2b5LBmlI1)#b$VEVslUDDcwT%?e zxcpQ1SA;Km$_Qi6JV!|{*51B*Xvv6BHsYrm$wpDJ^CuMP|>A-J2HT=*#YZPnX8t}KYzCDOd>{>TZ#?GfFpfZekBf%u*bmOS9dA^T2_dVWHICj!+ySf!cNcQt}hq(t6(bT?#N&{U^GN@0b+?LOv6xk zjAU>#TT)~`&yDCyPNWdxiP;sK?*qJH?t6EURISFMBxdm~P}x3WR6}(wmJ;F6Rh6MS z;;(VK08c2gSQ9s?q_cI|htm6phT4QN!%}mJ=67v`(S5+R1UZNZsErXpNhPy7h=;0#GfIeo)B~v39CHVAZk2^fFI|mHMc1tY+^*V2 zExag9GEa>6wYVY^T`BC%?dc2}NiJcZ!mz$r5^NI;MpbMbw~#p?dnP?0A2Tx!;^)HI z6+U`L#!d>VzOZnx8C5&oo#_LxXX15@0c>jGme z(c2Rdh0wiit@N`Vt66Q1`4I9vJx6?)OQ9#LnKY90=jQa9VRt7k+}NXy#77DiYST=uli51q_Qg^L2oHFOHQaCce`m8rU+Xl zlDwhch)@{{FTXk>2ZVxI8uELj+PDw5xJk3zi3(b*Xfi;ostX}8d6C)Oy~f9ht@%_h zKM%U&IoW*kbBa5LO^->){eiM8dPpvF>RQ?j`>kc00(o`)dnImb`k>N8O#Y0mP#rJm zX|P#T&Iw)c?FO#O>`--Km}_DtsI_c4U~CI6gA&~j8&VMOV~bohr0S(E=!1?uT_4zd zh6cL_D9_f#X8gWhm9JcltEx%v)u%kw=(45aZHrD@Vh}#nF!#EX0xk1noyPecQy(;l z-~eZ}R`pQchM=ZJF?wnvTAHbF&Xz3C%d?wDfn(2inal{DEhy-*3%j+@yZZXV;- zMe(=vJUlL2N|ASj{cu4V*w*=cO`U~T>h5xm(rzcwSPRI4XpFqtOvpq;%uBv!Qgh@y z&m4W{Kws`N;ChC%AAWx^Mi<{GoIzn(GDPGuxxGX1NjusrG;%aiy;Co{OmwWsqGy_y zj7}iLJ~hu9r&K6M^?3sLmw2RxN>WzgT8>tFVw6U0P)d%bT9tW{<)aeiu z7qrlRdOMtMN1tqgVZ^2o#whH7oOr}4{S>OFHf4<1eV-Kv?xSUgVhGV_ppgmZ1><3; zhTz?y5y>RSo3MdB%dbhhAMxe0+RxQxN&=>DatX6wEac;L76ww-M^C(y&`n8T30`SzvKk9KM$GgLT&8@S6AMm$8_!KD(qC%6vJR&S{x}wP0`0>uBiV+Gl;#U!ArU zOnrGcVTt1Ts^8Q7PBGZ_Xv5QI@pP896~y@N2Vy(_L49{@5XYC$sU0t@Rjc~tF}$`Q zT23CPZl1A%b=)6kpb%44k@S3hKne@pvc5YUEJJ`9VNV#jWVv!pCrjv-PRTb>5o+b& z1$=4yZZh~sePqG?xo5jaTiPfjXnHA2olemccyoTqad0`+1y6ux8|uz3$9k*V%XRqP ztNVE$7DLu6-1{lxJZ9CT6(ad0<0gWamx0&kYuEjb*Oz4^-It-rWaFn&-iDl_v z@ceB;4r0S-H->OouqqU+(D*T8j6ZcgmYQNN)Jm42JC8mwhS6;>?UhXg%>aDnCjq!DU-rbm@4!V-oriMbPHp^nppll_D`5^h)KLKO^R^U$1bm1#t z=_1pmyuuOlmdzwjoh-(X44Nd0>|(IQ60)l|PTwvpnn*n?4%z7z@2=?_74i{IG46kK z%eOmH;_70edG`ceIw*EwMQ38XB1wIA6~`DQ?ns<3^CQ-8kB;k^D7g2B(<77C0J{>U z$H}yNAQuBk$decHCa1GQfs{(W5A_6*C=>VYFoeL58`!Da4XBJG=UZiITGtMK6kdPu zj|D2=p)bZ{cl6;n1IycF)@58vJgDwx*Y&Fwa+sM2-eQmG%-k4+ym$nT2 z(eTB-4d@*MEGW|d(n_VtS8$GYdi+RBX=rLOHWvmX%;GYxC%54xaqr zt_KR&h`u;T*fnQc6gEzrA?!=Zs6CoLs>(nn-4xgmi^Kk`;vm;(&R@P|$Um`^SomL;y!xtYg^p+}pr@-m86E+6YUv*OcuzxWS!jnP zk8;*?xkv>ufnkz3=epAHciw<>1Y?Dq7=8)2BK9%!HG&ckC z)#jS!Vz%igRu7vl_o$@?SoP}0O^+Vq$5wIg!Al&|-EP}DM9Wh~a|>`zf9Pk{U4BSk z@+^avZc%WIUTsJZoI$m1xei#lE}G-%EvRDkw?!NuF`Ynf$VeUb59nA=S5~dg8hvh~Q~1 zp3yM}hMiQJ#E(mML25vkw)KZd9dBfINQ{nEY}JGMW?gd*k9z6KsUnE4;u}bhn|p!^ zV)m1R?OxbD=Ez!m>jEj~nYM&mWBv=7IMJmmUfYUnYaHu>;F~YDgq^X1G8M+i9(Bb!F-E#>Dz02_|1$PUj*=?1|qAb@cv2b#yvJu;vuk94%oqKvIhTkNl8^P2Ses8YwnKt`HraKSf?t4 z&JYtMumr8OzCjaNX-|vX+`E9LK(BCCTnSF5mdM!{o6f>j5*GF0B|&l+;{*kh`4tOU zYD`(#y(tN!-fIk^@evV@B$dI2UHV-!reHk+Ije*q z3uENM68hv?VJ_Y$b6RzC|Dw(G@<&bWu2W4dIJ%gAh{AW}MRvtkgc4xWL#fC}Coo=g zx_XUdN|B>^ZB(f6(L)%Udcwp3-?y*fLIlJQt0k%`)L)Upmo7qIqh|KCzS6aDld8WW-^rpd%(k2?m4Di9Nj3W4W~9O zzBsUL0#vv$RXY<89w_o`pJ@n?JR53vZiZ5Jg|a-hMi_(DoyE@DAXpetxSVsw^kDJj zx+LGDz4$TZuqzf{x@(a*_B`3~z?DXInnJk>4gNV`C>N8_bu{KEW~*l?d1ETKaNU`A z65la9MER8&){BAX7R;78pT(A)FS?Z$wtLR0rZuX@te4MYd*@sV`HE#UHX1WYhWs11 znX{tV5k#!seF*8G5RAivuaxgU_U2HH^uu)D-blR_`O*Ka=w|v3#zx9c4(2wdf9SiH zvW(?h2eTdNh9Kh9vblR0TS_{eT~Qs)Z05ZS+UNNcE(a5y{O4Q8hAzVBt@x{RK2jrJ z`(jd_uk6AfIteJ0$738+p}8TRQu>f4GH~Ej{8R!#I&wF|&tAqk`k4pF(9Wip9{Mh2 zbqpX(axF+hyePH(o%8wK3+ADNs8FoQ+P*t+-%=y@YEbDpy7R=ZyKXcH%?8s(~Ac|dwWpR(D+sqFz%;gT}V@ zCDwLZtHT!co%aSMqC69Yrc}x^!Ci%OZm>)O?(Yh_ChlFhhn>=Z0(tC#?)&*Vm8ZKg z9LURZ%Cd=e+`g?NLZP{@?ZbU@J(apUSuj-e;_K(CXWJf$VvQms2GB?sd9Md#1ODF`HA}4O|`wNEq3yMw0KU#fr=4=F|H`&|1S$>qaj+c?Gp`wGWog;&x zt%LC|;lIsv{IAjVCc22YsW&CW4my?df|~ZEe4n0*P$fD>A0Z>#Yt~wN+z}}VXU_8- zzwh?Ei?)i$M91xW)}=4sp2BvYPSP5bS^P(8AyVjAsIZU3AJf74Ol5qdcnwog%gWG6 z_W_V}(<9+23ke@_@tsuz8o010ViR&&Aa3t%YkV}VG69)%-_gq*>sq?DG7FwigOnv>H{T$5BJg`>wgE}2pG z16Ez0_I9Uo{MhLQFlj~Mn-^$L%^q$CB@ay&u6-c+)f)+xdJWS*`Dk2D*Jc(>Kd==H z8uCsr@gao9X_@YZYyD{f?R+Z^wMuW0^h5j5A80Cxnm60Sc7$tLDq8E)Y^87oNRL4JBIZqW&1CXI)zQ9xy{!-p`?HkkVBM`_+ue0qU!Ahs6*y<1r?iqy)_ za0QEa;oe@%;z7(T>M7=d!~`SFBR|ZhW5+_6Vz6=ZrIAV2`3-MI+xH$xAC28<&fnZc z8N>FFqHI)Y*6TtYqRGbBotxazlL(x`WCE}UDEjK_kXFRy9y-@%oO!^b%GOSr4^QCTAZ4h0 zq;Od*8-(d`OfIpUKM9E1l)?w|j4);Um@+K)s@tYUKEwn#Zt5}m@APwRjn{}gtXUDB z3xp;+ZpG?vW!g1>t+P6gbMSL1JoI?JZ-#zJc~`ifeqDKm=emiHy}sbCqq2;NI)4u( zf5?w9Yq)0Q5HQpX(J}C#ed%h*8Ib&Q{`$h@gHH0jt|=RtK!xV(TbTSWR|Wz~_ZCO| z^9bvIZtXw&KMb@g%KV+d-{38D4Pd@xf z3IO=M^|Jr}=OBLP^LzLEPfoq?|KCUaS1U#%>2o~i{K9i zf2KCSll~qa{z+>5RswyKgyZkQ;_n=Ok7xema6|G3hrdNPzf=F+BmYSY0635V0RQEm me<%OD9sMi$BgJ3H|7}$jWgy;ky3u7r7-?{2qr{1M z`7MkV11*4W;Q(N@N3g|bX7Ie5{<)^uZlh`K)G8o@+{zsh_F_JY4=p=%8k`0^mM$;^3AyV+;~)2}JPajM?Mc>6Ze z+XKe85s+mV{Qeh0jj&RMd8)1#3L*@hpH=UA~vNC~H!{6_e(d)QE z!Kk!fYy#KsE?@mo@-;HyUPD*g*3jIJp6=)Mzajg7I8Oiaub0M3$#gTo2cC&O1`XWIu0{jj zOE?LLwh$?LdW)?f)ZuTHK&R)%4r-+EVP&l?mQI#|nWlIdMlL$|L7pww~)2U#?pycBQ zqVuHqsP##GT+_QP2bq1Za8edn*}$H47&o5gHJ@1U?G0Zrr{wWe3fh33p3!2t`+zyo z)g88yf-$E_rCz4(J7O1Y1M`jx!L)XiCwE%u^Z|Kd7UWx|aglzqtSc|IT9)s_87@8S zFx@2s=Yzgs1Vw9q8zgrDBq@_%0KfqZ0D$@VPtuuBv&(XKvZd1buqQ=L~6I|@(y`pKuwuIBx$}pEDrP4$$65j+x&__1TA{N~cZ*d*FHw9&{~mgQ7(rR+XXClt%ii!TkC zD2paS+(Re2k7`*2mxnax_$#19fnYRqOx!6OW2sM;$J-J9(BYk+HD7E@0@w4;H^?c7 zm2#%_336-qOtQn+*Kv!r(`jVWf3XkHkyY)WKSvWzy|-UnlTR_rpa8@3u;_HTT%e`A zAK85qWejUBd{?jg9!*O{p0v~MGId>~C;zNuhfg-CfXem&;Cl07VGU?GhjLvL&+dE~ zzJ-;)4B!>$@klppWzZ6_!Xz zDaBv!W87<%SRL{pq|UMoTW6bn8|_Dlm+0uWN$?&-`=6V}($WTE&|ONdlCrSAexP6D z5Sbd2IfYIWJ|B%iu5IvRwjAFfa-^hHFa|e0)Q8~d`VkMlJW!&1%{-$6!pQ`KAhJLL znYk1x(3fc#9%6xof~>A!#1c^$lPmfKU+m?@nd)A71F@pweTo9nKBy_d+A)^8P;J1M zL%UGG8RNnLmdFBRF!+K#aJpL$1rXNi@P=* zP=gAGgK9qBTJS!(HG)1dWVQI0R25QU8{2-Te~s;bFOf#@>iLwfc>x3x0Kf)7gSkC=GV%a437D~Vo4Ww<m6Z! z)44vMV=9_Aut><3_(?d^jl2HL@n*Vi2QI>*c8euMPh1v8lkLmiWv+9pTUO6IS+ZI+ zqCzmW=3y(VdaDKBi?mX6R|$6vL(YV;E1B?*L{(ro-|!PE6qoEb+>K4={5bd{Xd<@5 zQ>O7*_>RP`$qGMdyFTe1wEnnSYyN`mL$BuUShNBG^J#VB9xNJEG9q%io#RJ%yk?^I zDCJApXs5U!I})x!Vnl)x^q!|Q=KdM<+h|6E?NoovsQ{?hK%LkCUEjDt^uWRQaf>wY zH85InP6>CsRo=?n62>!^&QZm{Uf0c-(hm$#HA|`Be!DHqYjrZKCoE5h-DBZgFA#s{ zXp-U<;`HDEzzPBYfcfe{|0pwd#)gLWcJ#k)j6ds5dYrmdE(0)NUFFcL@=+SzX9_hy z(L$}(L;a*|ybr!Jl)m(2rFQA14NPuI+$Ds{hXwxHX>X(ZQMUqZ(f491HI_Us8JVGr zZK_oK{>TVzl;XQjS|GJqRvy&(rLN6|VOx#m370p2w2r%23-I2Tk^bGpii|lTC1o`pxt{85Y2{W6|D|!3$h`9*hOcwbbHWr#oEmrs=k-t*{xmAFKm^1aco*?nSPpK zYq%MowMZ&5nDt68=kZv!jGaxID!jP9YH7LLAHHgnsAiE_+T(`z$gaASk!dHem@6f) zsNs!D%`g);b<6fy80~$}>kLHPljnw=sGr5TUy?kQ#QhN+6z>-YR< z3NKqF`$@Jd*LqnJ5hjZmw8)xYmQ4ZyzX+6&hALo;{q+aq&?nWBvNUZ0H4h^xMzhQ!|CV7_=(gSwzp4D#=LNPM5-UEcS|M-%HdSc?_Y>>-TdqI`woa(1TpT9_BQ z|E{=uv`_(vkShx=(sZdl5F2Vri@M$>piZ;|HZsi+P>9gDP$OCb2v7LhBPiA#AX=PU z?hDyc5Bd<=*+Y+~Po{|G9f2p93Z+wea2_#QIE}B4yH8cnlGTX-{}9$`06Hx|eQOl- z{Rr!{$EJEiHmT;Wj$wZ3riJfMH>su+m6W-Xq7fe-p;jIclcKItVwzx9k*64v9QUr0 z_yO0EQy>m2c1K2b*TkSDY^o=2iWF>Anirk;SsQfwV0rN%X&=K7!ziyHap7kf`uA$q zg_})|`G}a@-bkl%tf)D;KK+eJV(O7IH5()cBQv|d+8oKIZDWyU)b{!I zF=%X9Z4(ahOR!%-PFSOAFQwsyEz5)qgxkw_D!iwLdJ7(Mg=!E<*9RzDYsl|sF9Hhz zO!O5;%r>me*J&hXo149k?TUD6kNCG-rp7(xaO)?})J0M_45_)zo%li?8oo&f5;S~b zmGkX?I!b(^uI0}fP=Ra%@a+WGm=wi{TOk<|KCEz5%6ZKwc--jS+)yT?75?m2BkT;< z@YBmr&zKcaM>e;Qw=ECuw31b6&l>A*@2_kr9M}7_tmxal`X20C+WEA?zLbV-Tc>^S zlA~EoIe3|$gny{mu51@Nshy)LbJ+#kZbZki;HK6u>kUKhZF*Z7P(GHGtD0To&5l9j zb3HU=Iy{j0#U7zZ)tH)MTF8)#h8$wX03cTiZ~)AJ6BZS#po51dPBoi)2t?Y!OPnj7 zK67S{cI2vd`eA=I@9;Ytte|C$_cD-3YOA2&=cJ=bai2YOsKeq$Z8@Kjol(GX-YB^o z0<9!b52w~VQ%+LkWx3)E)O~%hfu{7_xcl~O)K3or(bVM~ICtYw0>t+Pc@+F>3~HYG zq@nsrElo&ZFD$TL1;g7QLDsB-2D%4b|1+>^hA>9FVN%Wm5~&v!$x)FY*n7Hy_ST(5 z{r)X~sj4|;f<sE8J|^vD5po01`@zAIpf$ejs4{VvN%??B1S+Pvcm?9&Tgs?f4JQyatkXDlze1T}@bs1^t-}Df)I?S06 zexT}DcgU8b(lk%eGr|rQlz)D&tY6+b((;$W^FNQeQI)ILd#dEzG|%%CxrC z5(5x$ek1mTkhty_$4@B;qeN(Uw5;fGQe#8cLtM|ij5<+!)+Pb048>5SjCmBfTh(-z zCb;=RM4*$w@-BChFb}+zA%Es5{Ml6#5=A_Hzj-HOGI|n>D=fAb$A6Od4Am+~Exl$}QB<;+FE`rY8?;Os3g3zDydMlHY=HQbK}L6273g zd*)xHIeFNZ>Kc1uC)eaE4_~y$8OJ0S>=XdYF@xXo^kQ4UO36?94x@3+^DrHY=2Xcr z+Ct+Ikpy-o41>1L_S}2y>8&x3uhOroK94KrLeT+pEFR7q%sA`ymzOvVZZZkM_cncIozF&OU6E=A^9XQdL&*FgNiH%99TN&0Wo7QmEHD z)ad~GjgQqHK`%6_rs`LaUPc-w*-ITp$X*y4@~m43bOqUT{4jEYM~>E9#?}E{f(2vq zazdtJ2`vxUHu}@ky{Hm65_`xJ+Xk1>qr*5P?6DD1csCYnNU=uM{-m}$(jMhrwwDWy z?8>a22C^_Ojr1O3B6OIl<@3$Gl2Rp#FLQ=w8039&IF8x6W*j_ZF5bkJ_LUOk8ccXe ziti?e=RPd<4O0)lA5N$@O2ftYVpm@Tmt~eGFn_?0ac?H5As{|q1gCki^)ydM%??dp zRNNPK`QCYOnSpVFQ`>epnBGVn#LR!jyVza47Nyl4N%!LR?OS--k4yOUWRh6)hoI1Q ztk8C8Ps0K@m`TyZdyWFf&sR+pNZPWpqZlUsx3QNxdWm+8JD-p=u7PDrD+5K7@*hcu zLbSd>mp=6OCK%=hh%eja>rmPWX#!OB-&FQNRi1YOZD0_TeUwdCAWFt1m<1IxN{Um6 zHGvAXAk$T09XX~pX_~HVhs#p-$HZTYR%=J;$Rvj8I)G#plNHw9Ztt0tf_u6U8fn39AuxGmx6Yt>`p zvFcL&T5t64b)L{F>GZW)CT@-K^oEU%Qr$@|u2#>lQ@4K*>HqnBCNf)@-1<808-)Ll z`HbZchO}(CP58=?RF<6hSGal#&GmYV4{PPz8q`iUQ#WkFyE-9kr%cy9`XghNholr? zdH`E#cbi7f)-$2Uoh~L)V%w8H+pxJQ^Vc?PpDI;;3yhsrWsYA=X5(A;)=|=3XLFeq z2&jPXcQT6)2e5r#jRoxZs_`&aUI`NS#>^{0!aaB8$U~Fp+lHCez;-1^J;e{Sz^2?7 z49$Q<83RIvLY1yJR9|4EqTg(=I4x^pz?5(amgdK9vhY(*<~Xln9^I;CpX#UE2t*>N z`|`BrVa-`FnNX%*)x(gG*4T|U{4g@_Yix|Qyjl+kVcyfBe}HlqA^S{CIaX1+gO})u z%+}O(e`MP$JxBJGrZUUo^>~fjTSF7_MX5gg3spp}N&S}}yLqA0R6n~gwJo@tpA;!C z%H}(FwmBog2$fX_jM00)Abs;@j*nXUchaz_u)=UDs^ zQ~RK#vtu3aqaC6|$@9Rw+FOP5+?k2<3|PM7O^BU>H;wNEvRf5G?=Qi%vV^MQ<$O(^ zUti(>Z@x6GUYoDLmry1;7Dlk4esn+5-Z}FWg*Xp`25`of6uPdJ#~ZU=IoBe;wc@i) zp0n@YYXk4x646L0V<}e7+T0#OHZfZtnHTqtXBXIA`683@wy$CgTv9Es10~Jad`z+*FMASx{PO`rE!*P*bVpDA?33?A zL+9tgJDU*#ub%N~u419}@FtfLB{%2Jqyxdr-C#O?;aMz7836~Txo|SNa!3qibsHNZ z3=C_V7CW1ciRq~lyzql;NU(?yX;FU2PK%twcqtYO%A+x492vhiC1~ay*M0ap+YUx{ zaE=AFrXnP2MUw#S92BHjAFkZ71@P%aBpCe=I4(b~&;6zKTcBQ%Hk6;dBiA#=X1lro zva2Q*Gv@r4AHcMvWbU;O$l1##kem4Za7)m3ddeJ|KWzgT;8>)&0Hv?+WNI25 z#~le}C`iB`7LD?U(XU^I=xB@#OX6|;?$?OqS8@8E5Bc^L1ee0s9Wa5{5#N89ys-X3 zVMZgc&t|s zJF~L}FRr4 zsK#FJY3x_@pUV?kxy-~@x+yIiT6lrNSE8kcZ=Y-gDdlpU*NpY=n!B43<+>m^Ro(U6 z3-=ke@1;n|0$9gbJbjtCcHPxI$87t0g__G==*Y#B1K2rnHxfem66NEyN^e7@_<{{F z%x^X87Y3ViytEvJ+$^IR6KYC_Q- z3oQ!EFwFM&vo`YeX*(m;LSs8C*45K*U0gW>4lng+K+Zn z+LAX^X6swK9W8Pnx}7q-7$2+%*~|K8;mvSTbBm&=twCFmb7k}-uL%CaV5THsy9t4i z8zta~vKO)!9niE*!K&FMwSrYACtNX1lv_EcGhVmtA1PKx)!L0K5>`&fP1D3aP~A+F z_)X8m9?mjY6dbu#jV;WM=keAFiq%AA>Y{7muJ~uAl$FVH%-eFcx@OpDTw{ zdJD~hi?b6`4){h)EDu2?i{ui3MnOa6@r56P%0p`t0yb(Wno8DZC|X6(hd76+09G-J zi5!-PclA{$@xNBjFzwb2>|T@M5$u0-Znl5av&iM2^^E!o4|s#X+bdSeQNm(5v!Yaj zUk-!cPobkh_*Ti|CK8XVMcy(efghf*Erq~ykKU+k0I4*tfYz7=meNN#S-if*_xZ63 zp&*`Pd^wbQ`n>@C#=-E`Md97xLaP~oTj2c>?2_~PZaC+p_nxJ}J7b$dHf6ggg%TYplRxGs-NMt*q=Tm0*Zop1CvZ#U>o7FeB^K<)>^o|4BUJ zdU-J~tgLwB7%RuJD)$oE8&2^iLZdL+zRZ;=_#?!WTGTlXg$JbA#kxI_J7zY0jTNz| z`_Em1lr`4zPhf4?TTuz95oe{hZxY>siL1I#4vUY3CBDzJ?W875TIIf1wUT~=EE(X# zwm(=0s?C+9W36$8clnx=RgkqCRfK3}AT)*VOvM-VcyITU{Nvm(;?^S7^{=1$AgBFB zt+V(q`v`G^NJ{yOeJ!_O)b7UtC;EcbTo)eh+Z9l7UJVArc%|X@wAAYx+MN~h0;7mS z?Wxo3(Jg)3rh)Qq6+5%};BP1LR7WWKSYCeZP5yHB_}OJkUw)wXrb?ARoRlahfw*-X z#4!=i0?X26B4L3_J;?jzhO_d@EbS~`hcc}_?kFiJw>Xx6Op5G_t!|I+t~(b4JLB3T{nU?Kvob!_&dk@*4gaQl zd%_Q@?2_7HJ zD_T(E(8z=Y!h*DR1~x#>EYB5tJGw{w@a1#g-nrK;-2Y;rUhC8f{FG235&x7?{hI&V z8yi{}(*L^t8vP%ujYi=#ptVB{yzq}`&W#+n>2gjKvR|LNZYF5%h>FDrYK>X*%ePRY zg23+2Nce!7OiK8yxl)8e8hb-F?L;x^kVw4*bK451Zia@oKJ&-wInguEobf#Gwf6V3 zN7>!Pl_Y1w5tHtU&BLAE;u8;skDF8#0)R zW*^<{jhC#osP{rO0TtW~By9CBl7@FdFD@oVC=;ho@}4Qo=l#k&!E{V9*iDaK%6P## zYOuIX`tnPejai-?ll3LCj;FF)reRIl+Va}#yEzY79&}fytoT!&?@yT{xpH;8yKrO! zt&TU`JQvPpXug6N-tHl^@gCN7#RRZt1yAm{W2~CjEsx^12GDSD*>`b`7OZ3Mor6M5 zRz}eA^!mOv)h_M5#lp}B7!!7fl8crpRCh23Z)tsL6#PJ?5IB!7Zqr2u|DX%xKbU>8 zez2m6M1-ajGt=r2JcT#m6&(YYQkr)IsI?;R?6R+ab$-4I+kbKS-itw>`2vSGX_&{P zl(<49ooLuZ@ci8W@^s~N(EjqgjHvxQ7?EW7SmO2kJlnAT6z{5P8bGP_d{?5P?RE8o z-s|?6K>JxjNHzdmdlUrK12m?W_zEex)YWzb1Dk}BX*T$2h4smeH$DV^dgDU6)xOW!z*4fm>1yqY6V0dpsrHpL~DkcVUjdCEjF znrOfTQA8)b8HRv$onhK`VbOTXQE|{tmvC2g$B2OE`((qu2j_h2V|mU_Mrxc#=#l}U zALg{53|B;{&M#vbB8BaU^Ck9Ty!UB2pNIl`_Us=R)%)4xDO^vdT>LrdNrE2Tftwr- zwgqB}eV$a~M1qX(c84JN_O4+kZ#JOPj~#9l#A%$`d6Bq%z*Pzq!GoU-$#C1g$~3m( z&zt*%P!C@Unj6k%W{n*jR3s`J6Cib+lVzg#X1X8hOzamMUie=6L01nE*+9&JnfHHb zlL_``5}Rjjq5KgnPHiwg5PP<1_q8q2d5$BbYN7BB{HtZasbYtoy{vQ3r+vc>n1COM zTfHXnBFOgfzHYTLM<)JdtrF`JPG8FdcH7xM>Q~ZzUbWZsg>R~YC%tB`9|dPN^Ci|H zPtGAxX@)==ehLU)Q;Ap@qHL(du-Js82rqSgTQGPO`Wb}=y#3L|^fRLJRU=xvL~9Lw z1+G?!?e(T-K;0;?B31!(dC+pJnbyKm0_W_dt#+{?(F!hg*>|r#%cj-WBigs1NH^;% zr5aDcca*b}2O0`}Bh%4=7?v^um2X7PbqQmw>0GO&* zbhxqmHe8j@7a4_TkwCHDYdlceUG=prah}aiKZFksApy#IHD#Pw=3Ao*Khwe0v7grp zb#aivQK$KTPoO+E0JrLPu}^$BLFsD1VLR>~{GD#CT=Xu_AnZpFpGm}-Ly|5LNp~=6g3TFySD~-E*TM!D} zW4v;8d12MnebS(wz^5_S z*5!v5x&6}K7)tc7SXjt54}ZpjZ#L`tCVy6W_VuLAvtllh`nq4b%0$gX$SUpB{C?B% z4!J}RqfXVZ>A`jE#5@)c{EJ*N#6O3D-y4_aS?0viU(b`url@9BgwN2Pv>%=Q2iy(4^HxM5-_xWXnY$gWU+%daNfa?3} ze97N4tO&P8edaT;qDofWw`Ez^*w^{NH=nHtJ7V~$aUrfMF%YQybSFw@x^-)&EN5L4 z1Qu`uc@}EZw%7LYn;AB;_;4fpBPyqG0p+JR*a=$gY(*@~xt<&d!dKad8}1KHz73ce zc6RC=`I`=BBERU`@1n~l^mc>d*LG9owcUL4N1?Z~cQH4#`$@y|lq}3%H{PCk7rcP? zr$dh0G%)oN(=)OMLs@voC3?dlMOxu`d1HOgZZeKqxbNyGJws#)r|rg9Ni?TQlwoTP z`)tdYa5eog8I=x0OOyiJ`OrGSNsfxX6itL0I``AG4e@!2mo39wH+~u+@|I=mHrr3d zBC6M57CQ;BO!m!C!x6)y84X?NV^I6(B?^liw3#eAgm#Mbsrr!sC^mXg03%L|b9fsI zcj}0TE?k|yS{Bb{Pw8!n6JZ>(WNfZCllmcc?14OLCx23T{uI)Vgqxo>FJBN%}S-MdE8U>UdsNA~mV$Br&mvi;CMUma&r;vI@ z@3(!VG7_}40tk72V?t}WMFt){4%@Xth%=Z^TTZ4_O$%3UtDDk4JSukxy`zXTN1pXJ zff!q&wAVBpF@;&#`od_H{B92>^8hG_`LdvIThBsHTqjN!a<0XSdUcfzPj20{+W`xnFR+X>< z`*+f;8M32W7q_qAqWA=ls`%i;mhN#0fKavLq6E_<^sa#fk7;Pu9@jwQrp+#!E2u8- zk9CFU{#qdW>)P|_`sfFOy{64br{5Y=HshWWl-x)C6E z0`=V3V_jQA0|k3q6HB9Cu5GWVX_dx+>hZbu#oO7+$MU2)L{{$o92Hq5==3#e zleJi>@2L4S>x-v!u4qif&B3PxRq0hUDo$2z9z^3W(k`4DfPO6e{~5WBMvix#lqM zfG~TH%?A)F5|#52PTQuj62*%O8iYQ4f0%tuqhi~Sy#eTV2Gz{GVv0|-LBcR&#(vd9 zKh%cZ*$kB{z4ioap=G?x?pd#ginb^&Y4}k0AX$w?D7NU{X0wuW8w`4s3biE@!$lWW zht+DBoWgVNXhIcHIb~tQnImQHNYMV6MJ@Iwq?pZy;Ke3n+G0Zw@`NxJ%_Nr?{(LAh zDg^dJf2zBo^Wpx2aa_fr>UBKQ?Hcnuv_;j_;Q3jyEY1Cs*%KdDl5^0QByIbd%R&wh z43-LRueE;vE)!7UBdy z9;qxeneh5rUuML%*I@tPOT#)0ZsfX0VcQDoQm4^nqgtG88}{LxHq*T`AK%w#*qW=l z6UZ~BdmEp~yQkIcYE1`I^CKn6bE4c&nf)qdA7&fZ0%sZC5v;o-C|K>^a%kFPzBM|U z;9$SWSSy`(TkQu7Att0UG2zHt2)oH^a>JPP6;ii>*6cPdgM-#|!+`I>yagsZN48I| zr~#9W()o3AzP?~V-;Qy8Jpo;ty26kp)FB`yxdUQB!-AVj8j$J}g9-R}XM~3DC>jt_ z04p70VoJl{!685$n}rJDbbkGCyd8w2K&o_@j7<+k2RGNO-4G1%z9CkNb(r-1dAH6H z>_|hQHKEUe0I`z(^;aiqwW&QpIMB5+LJ)>2;87eRJh7`1qmCl%aY7sY0)uPgSvS`xDEIZ zFray?9I(WX+jUt1cXnAykkT>B`n&Hkwh$K69rVt4lfSahIpEFYvIPzkY|ig)eY9H_A3u*nz<}9>te1J)SCaj{|Gx(OROXja*ComI*j* za?Yc+Q`Qo8x;cUv+G5DO-5iM`KcXPrW=xS>PX%w^OKV&W;Ml!=%Sfy%DO>~c9ex1W z{ku@L)$3aRd(qJTH2l)>>V}=K<4NFO-B8!s`oCWIx@7o`rT z&?Ey?X4PeWj&P(WuN&l_^^w$(r+RxHj-2X4^c$!HS~E_0d0#FwMk=C|ux2;>>d7PM zjl^($zGU&&2)QFN4W+|z>9>X>LqROAbQnj1c4mq=htglW&6eE{+H zVMe|jEyp$MuY0E0%kT~@u4FwBFlG>1F{L4T9GRcm<_q4}--^uMKe3_MKh7%f2Rkxx zo_>r*%eQaqkzM`R!q-@sw)gGf@J(k4{`%Juo!Ch`H?`7+ehf;-ux##3vdY?oxPt6X z*;SJoL_|w7739s@OOrS&*l$F+PE6dP*_~D<>uu&zi2*EJ1JbEUe%DpJ*Is#z>Ep48 zFs*HJQ8gFsZ=YY&>mObZ0!sTzi~jz=!s?YDz1zZ?In68=w90ATHPZ{a`d;(y2aUFiHLlE`a2^q*wUzoY!F zWc(AQ6zOkKe(4&2NBLd7^e4*mE6@F#@A6B_^gGJ$nt?x2#<2eu<(Gosca-0^A^$|_ z#Q$5AUz?J@qx`<#^CwCs(chx{+Wq+*<@aIqpC}?^zfgW3P5%z?dz1So00ZqWfInN_ z-%Wq-CH^!8XZXYP_s-&Xgx|^Lp9o}3zYzX~dj4+xuk7egTL7S%836b1)o^yIRInw4LBeLWG5aIX#ul*OV05oyb8IcaZ=ScM$m!fPK zd^yG+Q-ZcgZG?A;z%tY*LyR7x2Wzdm+8T3wBFBZFoO<+)hg&4g(a;D=mwQrXAuVo( zBJ`!^Rn!~*Vc4LJo*6_9|Ztwz{8;8QNb}iaxto5xkN2^HlX1OV22e){0TmD*hx#Jo`Rw^`=OcWND-Enb)E=MW1)e3RS zrn7Rvm-f?IC_-WAT9!!hhJ$BAMs`b|zhMO6%Dw%t783*78tky~V{CN6_ikR1N(Lfz zRo4X7arzRAN$X7%+ez!YSzc*=dzig4$Z;Js1tj1Ud}$lQ*@VrA%tIz5AP-{@AuQS} z6XyZ>mr8#7B>N*SIuOph`+FpS#$PyDqsz^34tF#aIOVY5oHTW{c68(7{CWN#7ypY1 z_@}8uA*$+~+}L493b)~X-=>%2@uieKB^8?JbOM4Dm+)$0@)#+W+n6cwb;v`IuXso0dzo@B0u8JAPX;r+y96;hOZtxc!BI3HSN@SCy)_>_!AJlA46b8%@Rjj$ zo2%D4mdDHfiSm$kjw5^y{pweT-_J zZuN*At37erDD;U$w*U1O=<();R)jnfU{`=2s~`>VUVz;|cJaaZCvpyUI`(2SRvL{( z1-Y|YGZkH?N}fwiS#Kw20z_}@FoROB9>TZoL?zS2GL;av92jx49a=S;2x?jGX@vt+ zMF;08hj;(98=gJ6E^&s$l+=VZhPg|GjU(f&-xV_{s;>}+3YxsGXhJR#yF22Tt@1T( z0GNR8Nb3`D=<_QDPRM@b9{J%j#rqKGtyuCsrra@29zncbc@hBfO_JYbbXZ_iO~2Wy z&S;0c+OEvDfL%9DPSNPeV1tFXZLAsV%>HuNep>wolK}=b5*Mg8<*bI^wKn&85i#v1 z0yU+7poQbPZH{&tjxK7AqCM>3*OoP@@cMhHF1+q`er0Sv}Ib4+b?&(n7NXchXB z&o94kZ2~;Wuuq%yCW5xkHW8IT(%Cs?v{8Puqg##iBmSBFK}&5agn@|`Djc5cUNb_k z{MjGzIRbfN9cSGrXL}`RNq5jvb28aH49CXa??|oTsic7T4A60fv)U%SJ~v4yk4oT# z9E9T_6zO%bUnF7o~W4jH0%@pM;e@Ey<2)JPN1qhY{9y zT`V!r@muAL#%}?4u!NeE$9a+N_KG|+@Ez5w(H1{O>0R(C#36~TuiJ()m%X;ppzsu} zD6QC=o0(GGPZdmKs+yau8Ha_fx-7-}qak<7%U5xH)WO1lgsV?ylv*r+-_;@@!0N0l zT_`QlSQ=RsAE&5%BI<2*@K)UQVt}aFm|QFAg|}U=-to)bEk+mP`smj=wc(z>JM{RL zUUJY=rgn7A`HormsHraSix<*(%D%$Z`K3bd&h(e{Qw3Pm{Q3`0u^C`vbi%gRy{&j$ zE7uEH7{l28qlXtLvzA=i{C%7I5^ys9UDKu%F)B~tS1RF}Mh-wnfYbF~vi4`v{zu{v z;Nd2m^#9!r3K>=E;)aJ?;3NF6&XZ;I^y!C^1ea_V2vWjM9fgYh(Sg^OVQ-8`k}oC( z+XXxQU|iC*P351X@KiP}G&G2q(6JxYa-L(Zq@|>z;dcpFFZ2dsK4P4kp4DH}KTkU& zd?pC#;|zXi@byGfiI*5nRhE)xQ;}pc2RJx2sF@yesOda#YEsxntZ#=nI2V9^MF znE&hMeT(HRFl2PR8ISZzC6qDCFCfSkwELFmcAK6LEK1Y%j4$i#*-ORjf(!@u$oGZ` zYkY-B&ty!5Vjn}!HtC0!)41h)&#Y>&u!brwdE2F6*)rk2*#G_`@Yw4T1nB?<2^iO)V6+4Yjq&Q9co@agzyzI@C@t-b zG~XMt^ihzW^55UudFc4qkOTH;-#TixOJYpp^m;eV5+{v9;f{%dtbPg*)YcFi_BcKav+kzI!~9o30|y2 zP@?QVO>rvWe~dEYkI9?}WRB4f_4Ip7w(h9};VX?UE)BQ3-~ZlvJ2dJyAUENEhiBdq zS-#eOgVUUw8}|(J0|R?w$2wjIgka{LGxNw>H(nyjy*`6+d}4S)c2|w~**<5==P4Y> zg>ZBwD2Z|2ls8+K(zCvNU|fU5is0*D#MRmSn1lq7a(H;IqS_AyVF=Mav}Yd z%kQ&BkPIKkc4XqSfFL4t&3M&B^Qe1jnQI=UtGu3rtK2#=!|M_cC3~}iE-sUKRN0el z9gWGBPqSvb1+N}V zCF_WS>f=|69E#OdtOH#7ES0*vI$A883PbFumC)$KhiurYgbAfuY|pi#612~h9Fwrm zqZ9WXA(Bc|lJ=6q`;G(q*iPqz`;O-c?_Jf<8~8=!rJWck?)c+*E$eyxb6&qR3Kk%6 zVpn)Pr1v1Ffn|oCadICl?f--lr!)im$@}E=oM&Zm$Kt<6^Y0-ksHk74awv@svFr6I zsD{W|}m!~QenI0`|+RC)cz%J(0bFQc8jthih^6%x~^J+x_y$gqNg+ksyQX`gyjq@Y~ZhSMqpAsaBH z+>#;*RL;{>$a*NN#(wm2j3ZIw=4+2myDm0>vIRgnP1?RQnr|nfD|#t* z+X){bh5MyqATq4M^NJu9r7>8ll)Iv)t(--%tx!C7wZwp7m$jKcpKF3_h zNTbFTL43?Qy544m?I#MjP9_w~4JPgL1*`GwA#>j+X2b5WyUk!1~uTG1sfIXf995#1}f`TRdD=cLj5> zVRIdV?8}mKpmPe1AzPoy*JUy>K7lO@I95ILtt2b49hz0i>|7f0IO!^r+CyH&oDffp zfT3>mcEbpBS?zp1EZ)usedppY&J8p`Pq%m&*APD#cf2gnBh%eI*1r$?nh?pk!Y~J! z5diDDIw&lLZOV+j-bJpHbTE@N5fA*aKCjM|b$8QEV%qF==`UWV`K9k*1LQn-cUfM3 ze-k%49vE=D^-UJLti z1rE(*r~)V@<2{;aFpAGUbMN{vV-HVZEOM-5o&1GHH}3HvCLc|iyfKM5VY`s{YUvlt z-kCfD4x)=8KV~(`Rk|%`@9S9v&vWDC@ZLetVYV@c(-Km&y1(1ESG&kw^~Qh$t?YpS z6-vG%z6>@|W>!swz+QFq6X>C~5>*@ZMC2-D^x<`4E_Ilx#z|K_^eNQ2LbEeA_Yvuy{bH3P??tyPHm~NPIXb@^Q(>%Z}am5QUmMkE5bbi4>w(j4>E*S_8CrZL~|w- z=NWjnMD~HknG9J(Y7aO(>{_ujJ+(;GfLuu{mI)6iyi%kh(Z8>|4~St1LpP}pCwwG& zM&=8$3nWbSJ0fASm!$iHy)KPhl3~pi*!VZE{rP%^QgamE@q{6E%Gc4ZhqmF5Zxs_5 z`FweCSopXDAPdnxV&wOCI&mx8kNhEF9oH7r5DM-szk05e`8=^Qu&jOl^$k+;6QpL9 zqX$BYwZOgN;)Y^-u!O&El>?XQG_QWmknZCR-y0vU8Wqjfr`FmaKb3pt28|mVIWiF~ zb~)Vq9e|=&Q);Z)Sap#K%yp97xa*k5MHE=y&@P9HQT9Vh*YDv5N_Av$VFfUyVYfjB zi}Ss&Rha5tQpTi{kH+9;ym}R`ZB21gW~vC2Ubh$1LbP=+=+^ao+JX9?a^w$W6n8kctwzMmP~A(671C0x^JDH?^fzGJP=N+MRR$#Ua31y?l&r@U`8-!UQDdU8bE*3wb z4aJ+O7Z@7|e?f`7jKiBc+$S?{UME-mp-SHDDw@3+Mt)L<=AhUb`jV!5k`FYLyp9m| zFe**=pq(}8Wu(S%GqB*LbS+&a{rw1)3h-b-U*}PH<*OlLo)Ptj=|g<=bmK9=uXYLZHRhy>9;Pt!G6y*LjA%BlN@TLm&g$?6d%0|G@BOYu#57!g|(IPAlcspWP3h z%u43^s7KCbG?ED6b4=~Ybaa6~*%xvWZYYz-D7cj(2WR^df zMqL*uv6Clv_!zL(jTDa3& z2&^flrbpdY@+=vj>pPG%ZOcDI->#B#nkuXFjnQgap-SqIEZ4RFM$s~nGwy;b7ZNaK zAD4x?Jr&gH+(IJ|R;rb^aFo&^C(BhZ&H1F$u#`fesnmSVKP`oS^>wt8Yg<037w08R$mFDX@xxk~+AL4fRpHDsQbLf=ma}3ky zb$5#u5Ayxp+Zpxlz|sAEg?HaFgOQ8XeC^u0wl;2;+`eUGUKJ-HQoSo`(8Ivx^oxEs z;Qo1<^Rp>6pG&Z&QxV(8u{TUtefEAyt$`%7mn?IgSv*kyscDQABcoFEqBF6C>eewL z?c;(eIV~)sDh79J(#Q6m3Ydh~KQa^shz<$#c<)K@6^FI8y&IB=YWxOK>Uwdp7*flf zJ(VaLiJsQryx^C2;ufT{A7)kD@_#FTy0mSWa*6mdl2bXWDg~5crD!Wok8rvd501E6 zt6DHRQ_3gf*>BJE6N*tTb&PRcX2G&R)SLxRCrrR}zKR2FXp(v^JV7~#q6m-dG92FH zRMJv`%FbBWp3%HgMS+nYb||qm2wfhI0flSAh5Fxr8&RZ;GcQ`hCs`k210lD+?V-)K zmb3mO8FJ?ZrELK#?wL2%x5*q~i=mqH1D`gA+BHuX2K7_lymBq5Fe^aG4LiDYu4x3r zN^6Oy)HlGBnR+_)T0Zer2wyf;BG3fyOb2b|oFa7?`0QMwkUPa(RfSSD`pho9?t0eL z$9?uOpbj(low>E58*OX+xw=fT-(r?{6Wr^(-bKgqeafg_f5tGvL?#iF&k@r!OuhjsgBb;I^5U^aX-Zre>J=FwIAjaqh=^bXP5KbRhQ**FVOb z%W9)#>F_I!@E`ua+}zUK(Nfyh+|K!@r;EmZ#_Zt6mpKC8<6k;!`{KVXe2p0p9MBFa zQ>C3xbi}{&&C5v%_D15Hj2k7L3aPy6LcLVQdNWrze`c}j(Xt<#lTSNJN|+E#f)U;6 zF=>Q-xj$A_jKhIy%(|!OP!UV7l%Thswxk_vP&^!!{N%yNdV~^oqr+lIYz-i6rP$GI z_v!a*1f8poKh`i?>k;ovsaF1RBK0<>y?XGt+6B&80(c6-%EeN{)#ardm!*rV_0O5W zlk5M>JiwRE4>GP6!cF@6NYxK*!q?V3Jr>m<_XSB0(<2N1mFY{ET#(d)TCMzvzaKZ2 zV?^pnrP$WJ&q%ghl>aj!njDZ`Kk0XBNn8b!NEK&`^9;^qplh|c)~8$uejbu-wE`y> zy@|F7tCx;0&VW@8l`QZ@p#hYKu_) zH(`os)k&}6{3!FYn=AK=<0)NtzWKv9NJ{jdS@qjh3Lw78M=O~h%14{+L0Ph1`8B>A z?*!PJPTf)0zrJ*qs59`rki(dE(W3ghu7LeP% zF4o`4dJmmQy!r|mW0F*o5^gG-+==i)WF!#3q3;*`M`!FXd4?VjcSZ{M8!i5yozeW| z%m4Wze98XZG9aohi$4n;NY^yj%M?H-P3&N(g@XS1Ckq6KhmBgH<@-v;2?iHp4p6R* zehrn_lC1mLYTOsAc`3_0FU(3?ySAYSBjr=-Gx<;7udQQ5Ur>I0+)9lt%(TUu1gx`N zfqcp1Ov?CR@6f&`95;p|B*i3wxl3Sf07G@8FZD6GuocP&@0T~XvuoZWcOXCs#Tc=& z_*QAtAv_*$g?4D@TC}42@~wzfx_L4jwklf22Q}kE+}6yvgExDC>m!xY*DH>+ClV1U zZtHK&*E3(%BEk6GMg+xy>erpVRE_9A-cfwmPQNHWr}SK-CWXy+Nyi}xDT9}`;8XcM$@9B`-$T(q42Y2YGVn)W z`aAS@dH(}SPyP$~7qR~x{Z~!>0}BA`!O?$H*x%uQ-39*)_oDg}{NH<`hB6BL$pQeF O@WT%-;^MSF|NTETbaI0L diff --git a/test/compatibility/test_data/text-functions.xlsx b/test/compatibility/test_data/text-functions.xlsx deleted file mode 100644 index 5dbee91580c6c64ae4290141cc103f66902a988d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11008 zcmeHtWmg^B()Gqdkl^kf+%>@o1h?P>-E3^*?y_-0g1ZC@?(Xhx!3pk~;Qo-Dd*5?T z&V7Huz5Stk^jJM>bg!^)Yl~T1 zIe@Gj^i*7JK=wM!E|wN#nXu5b=>X`b=l^&77tcUZOuKw1D{|nmWRqAdgL$Q`@blsY zgEn*;HWD(bBLXJ5OkTo;g>_?~XkL-%{ud>}+sD>ACz?tfUJ|c0$sJ_MO{r;B{GUy>O*2OoQ zQKZC(1F~!y;BX%Qc9&eS#?#t%w&Pf7%qoZlxu^&F3xku?)z8dDLMhs~+v2ZibyUp| z2Kwd1uxZEO(GbBtvk4T%;*?eQTY~GKA(6QtepX5M7OKTg^j&Wlh0#IuDA{oGo@OYb zh6Aap(Rv)HDQ#pC^Z&T{Urflqe0ouooWdX6ybJ2P{JIo@CMx4BBH2i;;^iZ?h+6$Ii;8fm^(7IS z3V|QYTkmGCyMcuz{*QZoV1iObo2Ar#CfdoYoR-DhuTGFRf!XF+~`O`!VDl+UcpFwO22g{z*CMce6{ z`%L^ir${?QAFG2vvdwb_76?Zi()BE)eT#`joJ%y5_(QnDeJ7tK)wF6wvD z?Pr#GmXw08qL;dE5dF5-CS)!JqPNZVNx)}_iE9aMCT zAtf->&=aP&B82BCe!ig+%8_~Jp2DqgWj`v&<7jPJ(nNQ+{1IZ2W% z?8fR>u5I3=h^eym7`*5ZV#3I`!K<&+Qs*Oa#nUcfAm~;Rw)2CArHF9Ed)$&Mru(5* zy~Gf|mZ4?SrnUQC#Z!gOx=S&*qNCQvD9Z+(`@AnT%`C|&)}l*ES7=j%b(}iYi^$2B zAZDbo*ziNYLk0#?Bz;+aZTt)ctV%_1>c|h6GmglUDcynlvmxk>T|7ly<-v!&R)(4| zlxLqNY$lj+cb-VE4CV+Oo5m7oivyhUFBdxdG=bOaH`6w#MVgF)lwl> z?Q2t)B&9jAmxVMW)4l}T?)&X^-|#OSZ^qo)DU@87h3*-8wS!v>U%nbWmUl?e(PJu= zKWmnaN4-3Kmzq_`8zO%hj`Lxs6m;Xs4}A|79apsBLSYxrlFfO1BIQ468wDS80Q*E} zp(pAR0G>lV(e@8{`zv|>Ep<>&Vd&Gd|J_GX)S!76E3)`yz=Pj-i!HmSVxX<@xN?GJ zvX_rd46m#qyte1YFL&>X=NbAzcP?6gL7rC(BDWQoi!JZ%Gk)Cf0@7n~%N0tLa~_hbaLp{EW=)1mUZWW45a` zr$u(7U!Lt98m(lrer)fnoZS}sk3Q7&NaR-x4*<{;004MTPyB1?w>JfW9PC+sUD$qV zKuWZ>brvgHz_R-MqyBX&-g7x<#C-1l%nQrv_=~v&a*c8}@N1spi&kecX)QVyCF+R4 z_JQkr?kMfxfsQb9= z`%8mphN8#!+zb8mxsRbXaaiKYu#@NJ1Re^}juFfsG|L!!CWBn~w0qajgmi`&LS8O5 zQsC^Rczvj#NK>pyK!tLPw6P&IUvs@i!g`KMi=i~JUCC*@z~a%P7A(obxD)x_r9KFo zHg+#{SSmlO*dRBEE=sC_1DEnBJy@8@8(L6A~LmT=i5687k_c%$ECTv9zzJ%a* z+!?K!%f;)P-)$hlHqi7-BwE2dS9E24y7zTJg94uRBRgHpF1x+7A>_oS%M!cJic{$ z*9t7S+52toUG%!E9jR}g8tChJogL)08j1n&kQ6RX?ztKcob|H2oT)8C%Pa-+Xts%*^!48EE^&VR z;DOj`QocPKcSxn1yR6e`w0~%3kEC5j4}UROvKZeuGx3QLtYXEjJy_9V>6}aoi+6Bu zz&*IVQrmAJn7F8k(;f*|_KD`Y$_{NQrDxLG_hr~u7hOz#Iqh?L`SPi4muKX2ezGHc z0lCMsxIVd8lAa-=F|EY|!`(KG?l;brO}sx6fZ@@N);_QJ33O=~uz!O*7s}@kc>BI@{m_<}lw!<)@3P}#kEzqXPO-a|o z_~GzLtlACdVEt49eD5v%o$}+N-sHJ#Yu>@ zBI&Vi488tZE^4qKZBj^83`BzM8y+a|pT=?^bG zh)s%aT|O1qaTS}WM9~B-$^I~CzvBc6I7Tm>q!NG1ol9&kCtfO}s37L^TD}*9Mo{8c zX~v|@tFSCzv1OreArGvJx7>JvEZBj2i3wq`w;s|5h>_ZHwV`hawMWS&hPQ?xa!Y04 zmpcV)8?gpaKYEgkPL3xwb4`i83DuUrBU~v*sjniwt$e1Sk~^B)*t{T(FU=R2moH{W z96%BDl67MOke9zJtF1LK4b&gjOlZUE_Giq=tADnP(#F%AMwuF-lkAT~lw3@r&ydc@ zu(8KUNC>25l~(_Sd6 zw$&zmA4jRS#*z2U+!@moKQ>&UD(T+-Y(&2tziK*!y0;8X?~w_eIex z9PTMJ%Mdf1!J;_hjMZm|q|2`uSff0P*->T&I}w+t`)@@o;*5SV#J?Bd05hYk4VaRp zdwF{c2DWP%xu_V`^+~G+RwQ9h$ztLbT*8z26oc$^qsepV&EJ>PDe+TSVc=?pG)Tp& zmL$Xz@Yp~Lr@)kus2rY9naDv+)xFP0u9LXz%Xn!kSEzuO3c)7jT`Zfd2OQab-J3Qw z8^uCjM*xa-$ruhes98}4Fh5giPdp@1-z+|FM-mEDrM>d%JfM{ubKPPJ zRM@i*Eq)u1Z)!FCeTaj>e%;*Wng~@y5e1_Tzg|x;)<^83PB;E_ozH~J&dY4H${Fab z$CKgV)?T`q9G{#fp>dQxCnLK|<;hbIwG+4yG-YWu)qX(N5Wkm{R7{}mh>fsv zBLfx`;`Wq`FSOaXjPEx$+R$gFKF{hm!rAmGsO>H-(2}y%$;C{;aL|lYnHx&s9o+GcJ+F_0p&5fS)R5s7#l zl+CUhw@5A@2dXE1c<6n+KX=|~eSBCz)qCjw7!SHD^nQ5wTDyE7R`|5#I?^V?$Y+BqZCIM!Md>^&j5YR;!h?p#t7@904OCigIK;&x`v=SjP_Ged8_w2Z zGc3>+vbi!&A8;nELl2K$ZkooPLfb@zpd|U&Gm2pQl=O?yauUelXs6brJ;N9Glue~c z9LvX+3>YK-*v9SzStZn^R=@v5Z*m6 z>=XZC!DI|tl%zj7i(>sGVNdZzW-HQXn~Cq9Jg{ra;g(Iims^?E?P$W)pO1wy=*|Oe zmDkZOM@pr~i++^+4cn{D0XU(p3&iou75J0`$IExpjLxls=={F0>NzT~!4Dv6qLwCw zx@M9Y3*Qii!Lv6OpqaGvk)55=I5ksJ^o|qiG)zdE$DaP!c0TA7a_0BEVu0KhZW_j- zx1dEK*q>c$hO3e8N3b-5(P&@P@v41OOPtFzZ%FxU?lo+aRlt!-o1ufEOPBFBXaynQ z2kKh4StjIgbDuI8Un)z0g%TV-}pY@wx9+?Br_A1dG>zf}``PIjtKeG%*_3>s~Mf3Ujcs-her-2rwG#FT6Ayh#2R!?t4^U=K##L zOWWLeAhqWuGkGRq>6GwXH}7xh?9Y1|=lPDmPTq#~51<2zyLA+tIcJ)~b3Zd9Rr8!w ziFfc)BQYfVe~+a*F@m-3bajZkJrcsU;W>BAwaFJ(NH(k_KqM%>2s){jrz6s9 z&$~<)&(BV+JAJ8XLX0+El{t9lZ-_Rpc$saq?bpQj8;Teg99&KW*El#K(Fw}njOcy5 zTJWo;((`Q`&Ag^gs)%(7Bkv+87It@*rzRqWO)T8T8tJS_EDCM~zkZi?Uo2KaK?;nM z;9XW8nB(_LegTr{U9_}RY#98EkK6$6*i}9*J8n8`@hY8;W4P#*FE`UN6Sq!2vbb4w zy2dCp#I4o<)!({}99l#X!xq>lyIeN6z9~)^%FMw(-ZDt7I#o)ZcQ1M_-Kbz6zEqR! zKZ#-8c<#4&p7-^2S56tHuQkfZpvi*A4RTa3nmoEX#5ynORf*AtEV8FuRup6Xt8gPs|WTeWoQcphAq#0u)|>b9_gxb0Y9iw9n(8JhO? zvQWbJRBN)eVc(fl{P4m>k99?^Z#>Jwu&WQ&WNnec3`B6}Wwit+YK?Eo{x+I9zZRO76T*&g`MUgnqKwa^;t%ua& zrP|wTw|!Z4JbwEhg}xrA)hPd|&Y}Jc0C@3-(Azt>T7c|-Zs4<3Ex`+{Xb*z3-e@;R z15WFV2sJX3Q;ItS>BI+xhJzt_x?$PbBRvo93QoF2uWH7Z z6ETiNMaoif47UTFk2&E-(~x;n3&W`-v8a(-n(&P;<7zWU&^93@VBLyZhg>6RQ&&;w zjZ1QI1cddFdQF+kT7I08z?oQ5#SiS= zNVZ|kh-jW$KSv4|db3|Hg#2OthKLjmzG_sGbdr+AEs*ps8QaG50?o93wZrxtzQaee zIv2-Z7ixQ1ZzctZv-76gyaD}aw=Qut`aV|GgK`}>#nbY&#P6vN&~hm)4*cv_ee|v4 z9Kte>m$s@`d&)A|ZHW#aZ6k;v5zmN_)9-;!m6d#Ls3hCT+jK3E08N?zwKO*H&P9iV zL0>t+v-}o=RG|eK6-VIy=o9oI`K1{@N@+ALa_Ar{q6F|20?qm$6>Su)ZrIz?g>1=Z zi_y*_p%HJCgdF*=jkfBHAccNv@Bx9kXb5rMbP%E#vRrTfJM8}yydpT#A^t2{xWfVf zSpV{AQv*AY(K`n_Gb@u{t{tW_Zk5c6<@veFyYBQNDJffyOWgkxM#URxQwbu+Qj$e( z$sXexv*^~+xdH(^ibG%cqxS8qH2XI$&INEy>D;kV_UtW)&(j%IH2b&t_{uhS7@&al zjP;5b+Z$nli{hk0{yiEtCSMYxv#N)~l;07RZ*56)(Gvg2b{H;p|2jIwN#JVsDYyp5 z0Ry(SYAcpXF;8utuRaaK6m;I$y|GM&D2E-uJ#fvy%0Cw|Pn*4TaO_dYi2|*u{b+{- z#p7r5BZ8VuhU4-oCTNLycz0`+ZP?Q^+PKUDWRR*rGCjx2@q#5qz)HdI22KjLOq3kU zXY?$uiuT^Xjb8Dp^NW2M_MOlsW5XLa^A8E#g2#J{=_EAa2|(Mq%OiE3ivv{6mT$W3 z)bk~{xaD#UMx1)ydgb2+_ANv%%~D=6kj|4HU0MvI+|ORTz`@3iu<^@rmQp8nDLz2| z=DzA3k=KCk0&x~|gZ=Kwp7uWeYJ+rfx1bH*BT=?AM`U!J`OezA;$Z_Qbm01IJssS1 z*w4q5>%!4|uE131XdbO^$AQ?B^}VWhp8mt8{^q;l*tGWTu#1K=%Yfp=2SC{|J^z8; zHu_BLuA`8&cMn1%oj1+zLw)d|E%)-57-;PizyLkP)66zg7$F2P3ls_Nmg!^0I9_# zso3bZ&X@)^ocATuDFGVca=55)-k$kZBz!WJ;UABC@em*IF_w=@N^7c*!IL-475rkd zaMs(`SB!587Fe&U2*Sy?URtknUhyrw$Z|NP9`Azv;G7|JDCP-P&&wJ ze{`Jrm?;F0A}*LR6J&)u6lU0mC)0&Kj?rko!AHht)e1$&5=Iq51|&jfV#A_F7wf{X z#VsINi3uB8{@QBK5yh!xFjLimP4HwvE#dvs@Hk>8I9P*1%OL#)`mK7`wNStbKv`@}Xz9r=}+Nh;e`WU8a zRXLlM2(AxCgnHdDI&<4&b(w5bg94B4iw_oYTe_>0YosFfyZlut8Mt{n)-*~4%y+Sw z#ntpZvtvvuU12F=ytYh^;zbL4FVy^Tj9_>XAq?+*slzlNgz2Sj6t5`o4za*d+;1WVLxmz6iU{mPNu1@99u&ch*f%t9?9iTZE(VKtzHDb z6pmY|WQp?pl@0r21KzAykx;iF^()qk<~9DDq%Np=Nw)&T0N5DT}UPX5JA>DubJ>kzZ+- zol+=tGeY(Gtu+5J3A4}#2%g6aW|yKabg9MN4+`edqFr4$`F%KP^yBQku`xzk2R=CU zhxWM$`7k49^MhlY(<`2=*2Hdc>L6E!?`=EaB9`@jMcGe zJ4H|Y?52Be%9{;2C~azEP`ZQdfGWZeph8OHSRqS}Vsnb*-6bV&R{qeJZGtYx`DQ`(T_`x-el5~qE!Cz5W|`A|gh!B1;il7_ zxZ(Lj0%7h>@_FeQk@G4E-tvsAuF3)q#`HD3{JtRe6!4poonLI&#Q}q4EatZ~_^c1uF=WfA&|FwT#|3mMfqRih7{JoXw-@u>O z>?dmcrLpOE;P34ne?t48-u1U;kKe(6FEalL1ps^ye}Vr$CFkGm{9b7M(^41m|9gpl zlpTM!@_R1xPb;}k(c#ml{GQqT-N5gAq(2Qr5dAXn=Z@)j=e)h~E O0a~6y07lxMcmD@29fa-x diff --git a/test/performance/basic-benchmark.ts b/test/performance/basic-benchmark.ts deleted file mode 100644 index 324a66c448..0000000000 --- a/test/performance/basic-benchmark.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {batch, benchmark, BenchmarkResult} from './benchmark' -import {expectedValues as expectedValuesT, sheet as sheetTGenerator} from './sheets/05-sheet-t' -import {expectedValues as expectedValuesA, sheet as sheetAGenerator} from './sheets/09-sheet-a' -import {expectedValues as expectedValuesB, sheet as sheetBGenerator} from './sheets/10-sheet-b' -import {sheet as columnRangesGenerator} from './sheets/column-ranges' - -export function runBasicBenchmark(): BenchmarkResult[] { - const result: BenchmarkResult[] = [] - const sheetA = sheetAGenerator() - const sheetB = sheetBGenerator() - const sheetT = sheetTGenerator() - const infiniteRanges = columnRangesGenerator() - - batch(result, - () => benchmark('Sheet A', sheetA, expectedValuesA(sheetA), { numberOfRuns: 100 }), - () => benchmark('Sheet B', sheetB, expectedValuesB(sheetB), { numberOfRuns: 100 }), - () => benchmark('Sheet T', sheetT, expectedValuesT(sheetT), { numberOfRuns: 100 }), - () => benchmark('Column ranges', infiniteRanges, [{ - address: 'AX50', - value: 1.04519967355127e+63 - }], { expectedTime: 1000, numberOfRuns: 100 }) - ) - - return result -} diff --git a/test/performance/benchmark.ts b/test/performance/benchmark.ts deleted file mode 100644 index 077cef3749..0000000000 --- a/test/performance/benchmark.ts +++ /dev/null @@ -1,169 +0,0 @@ -import {CellValue, ConfigParams, HyperFormula, Sheet} from '../../src' -import {Maybe} from '../../src/Maybe' -import { - average, - EnrichedStatType, - enrichStatistics, - measureCruds, - reduceStats, - Stats, - statsTreePrint, - statsTreePrintCruds -} from './utils/stats' - -export interface Config { - expectedTime?: number, - numberOfRuns: number, - engineConfig?: Partial, -} - -export const defaultConfig: Config = { - numberOfRuns: 1, -} - -export const defaultEngineConfig: Partial = { - useStats: true, - licenseKey: 'gpl-v3' -} - -export interface ExpectedValue { - address: string, - value: CellValue, -} - -export interface BenchmarkResult { - name: string, - engine: HyperFormula, - totalTime: number, - statistics: Stats, -} - -export function benchmark( - name: string, - sheet: Sheet, - expectedValues: ExpectedValue[], - config: Partial = defaultConfig -): Maybe { - const runEngine = (engineConfig?: Partial) => HyperFormula.buildFromArray(sheet, engineConfig) - return benchmarkBuild(name, runEngine, expectedValues, config) -} - -export function benchmarkCruds( - name: string, - sheet: Sheet, - cruds: (engine: HyperFormula) => void, - expectedValues: ExpectedValue[], - userConfig: Partial = defaultConfig, -): Maybe { - console.info(`=== Benchmark - ${name} === `) - - const config = Object.assign({}, defaultConfig, userConfig) - const engineConfig = Object.assign({}, config.engineConfig, defaultEngineConfig) - - const statistics: Stats[] = [] - - let currentRun = 0 - let engine: HyperFormula | undefined - - do { - engine = HyperFormula.buildFromArray(sheet, engineConfig) - statistics.push(enrichStatistics(measureCruds(engine, name, cruds))) - - currentRun++ - - if (!validate(engine, expectedValues)) { - console.error('Sheet validation error') - if (process.exit) { - process.exit(1) - } - return - } - } while (currentRun < config.numberOfRuns) - - const averages = reduceStats(statistics, average) - const totalTime = averages.get(EnrichedStatType.CRUDS_TOTAL) || 0 - statsTreePrintCruds(averages) - - return { - name: name, - engine: engine, - totalTime: totalTime, - statistics: averages, - } -} - -export function batch(stats: BenchmarkResult[], ...benchmarks: (() => Maybe)[]): void { - for (const benchmark of benchmarks) { - const result = benchmark() - if (result !== undefined) { - stats.push(result) - } - } -} - -function benchmarkBuild( - name: string, - runEngine: (engineConfig?: Partial) => HyperFormula, - expectedValues: ExpectedValue[], - userConfig: Partial = defaultConfig, -): Maybe { - console.info(`=== Benchmark - ${name} === `) - - const config = Object.assign({}, defaultConfig, userConfig) - const engineConfig = Object.assign({}, config.engineConfig, defaultEngineConfig) - - const statistics: Stats[] = [] - - let currentRun = 0 - let engine: HyperFormula - - do { - engine = runEngine(engineConfig) - statistics.push(enrichStatistics(engine.getStats())) - - currentRun++ - - if (!validate(engine, expectedValues)) { - console.error('Sheet validation error') - if (process.exit) { - process.exit(1) - } - return - } - } while (currentRun < config.numberOfRuns) - - const averages = reduceStats(statistics, average) - const totalTime = averages.get(EnrichedStatType.BUILD_ENGINE_TOTAL) || 0 - statsTreePrint(averages) - - return { - name: name, - engine: engine, - statistics: averages, - totalTime: totalTime - } -} - -function validate(engine: HyperFormula, expectedValues: ExpectedValue[]) { - let valid = true - - for (let i = 0; i < expectedValues.length; ++i) { - let expectedValue = expectedValues[i].value - - const address = engine.simpleCellAddressFromString(expectedValues[i].address, 0)! - let actualValue = engine.getCellValue(address) - - if (typeof expectedValue === 'number' && typeof actualValue === 'number') { - expectedValue = expectedValue.toPrecision(8) - actualValue = actualValue.toPrecision(8) - } - - if (actualValue !== expectedValue) { - console.error(`expected ${expectedValue} but got`, actualValue) - valid = false - break - } - } - - return valid -} diff --git a/test/performance/compare-benchmarks.ts b/test/performance/compare-benchmarks.ts deleted file mode 100644 index 0503ae32a2..0000000000 --- a/test/performance/compare-benchmarks.ts +++ /dev/null @@ -1,93 +0,0 @@ -import fs = require('fs') -import asTable = require('as-table') - -interface ResultSuite { - suiteName: string, - results: { testName: string, time: number }[], -} - -(() => { - try { - const args = process.argv.slice(2) - - if (!args || args.length !== 3) { - console.log('Usage:\n$ npm run benchmark:compare-benchmarks base-benchmarks.json current-change-benchmarks.json output-file.md') - return - } - - const inputFilenames = args.slice(0, 2) - const outputFilename = args[2] - - const resultSuites: ResultSuite[] = inputFilenames.map(readResultSuiteFromFile) - const benchmarkTable = buildBenchmarkTable(resultSuites) - writeTableToFile(benchmarkTable, outputFilename) - } catch (err) { - console.error(err) - } -})() - -function writeTableToFile(tableData: { [key: string]: string | number }[], filename: string): void { - const tableRenderer = asTable.configure({ delimiter: ' | ', right: true }) - const renderedTable = `\n\n\`\`\`\n${tableRenderer(tableData)}\n\`\`\`\n` - - try { - fs.writeFileSync(filename, renderedTable) - console.log(`Output written to file ${filename}`) - } catch (err) { - throw new Error(`Cannot write data to file ${filename}\n${err}`) - } -} - -function readResultSuiteFromFile(filename: string): ResultSuite { - const suiteName = filenameWithNoExtension(filename) - const resultsFromFile = readResultsFromFile(filename) - const results = resultsFromFile.map(item => ({ testName: item.name, time: item.totalTime })) - return { suiteName, results } -} - -function filenameWithNoExtension(filename: string): string { - return filename.replace(/\.[^/.]+$/, '') -} - -function readResultsFromFile(filename: string): { name: string, totalTime: number }[] { - try { - const rawFileContent = fs.readFileSync(filename) - return JSON.parse(rawFileContent.toString()) - } catch (err) { - throw new Error(`Cannot read results from ${filename}\n${err}`) - } -} - -function buildBenchmarkTable(resultSuites: ResultSuite[]): { [key: string]: string | number }[] { - const testNames = resultSuites[0].results.map(bm => bm.testName) - return testNames.map(testName => buildBenchmarkTableRow(testName, resultSuites)) -} - -function buildBenchmarkTableRow(testName: string, resultSuites: ResultSuite[]): { [key: string]: string | number } { - const testResultsEntries = resultSuites.map(resultSuite => findTestResultInSuite(testName, resultSuite)) - const changeEntries = calculateChangeFromBase(testResultsEntries) - const testResultsObj = (Object as any).fromEntries([ ...testResultsEntries, ...changeEntries ]) - return { testName, ...testResultsObj } -} - -function calculateChangeFromBase(testResultsEntries: [string, number][]): [string, string][] { - const [baseSuiteName, baseSuiteResult] = testResultsEntries[0] - const resultsWithoutBase = testResultsEntries.filter(([currSuiteName, _]) => currSuiteName !== baseSuiteName) - return resultsWithoutBase.map(currResultEntry => buildChangeEntry(currResultEntry, baseSuiteResult)) -} - -function buildChangeEntry([_, currSuiteResult]: [string, number], baseSuiteResult: number): [string, string] { - const change = (currSuiteResult - baseSuiteResult) / baseSuiteResult * 100.0 - const formattedChange = `${change > 0.0 ? '+' : ''}${change.toFixed(2)}%` - return ['change', formattedChange] -} - -function findTestResultInSuite(testName: string, resultSuite: ResultSuite): [string, number] { - const resultItem = resultSuite.results.find(res => res.testName === testName) - - if (!resultItem) { - throw new Error(`Cannot find result for test '${testName}' in suite ${resultSuite.suiteName}`) - } - - return [resultSuite.suiteName, resultItem.time] -} diff --git a/test/performance/cruds-benchmark.ts b/test/performance/cruds-benchmark.ts deleted file mode 100644 index 5993009c72..0000000000 --- a/test/performance/cruds-benchmark.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {HyperFormula} from '../../src' -import {batch, benchmarkCruds, BenchmarkResult} from './benchmark' -import {sheet as sheetAGenerator} from './sheets/09-sheet-a' -import {sheet as sheetBGenerator} from './sheets/10-sheet-b' -import {sheet as columnRangesGenerator} from './sheets/column-ranges' -import {adr} from './utils/utils' - -export function runCrudsBenchmark(): BenchmarkResult[] { - const result: BenchmarkResult[] = [] - const sheetA = sheetAGenerator(10000) - const sheetB = sheetBGenerator(5000) - const columnRanges = columnRangesGenerator() - - batch(result, - () => benchmarkCruds('Sheet A: change value, add/remove row/column', sheetA, (engine: HyperFormula) => { - engine.setCellContents(adr('A1'), '123') - engine.addRows(0, [5000, 1]) - engine.removeRows(0, [8000, 1]) - engine.addColumns(0, [0, 1]) - engine.removeColumns(0, [0, 1]) - }, [ - {address: 'E7000', value: -1.17344394901827e+23}, - ], { numberOfRuns: 100 }), - - () => benchmarkCruds('Sheet B: change value, add/remove row/column', sheetB, (engine: HyperFormula) => { - engine.setCellContents(adr('A1'), '123') - engine.addRows(0, [2000, 1]) - engine.removeRows(0, [3000, 1]) - engine.addColumns(0, [0, 1]) - engine.removeColumns(0, [0, 1]) - }, [ - {address: 'E50', value: 1347}, - {address: 'E2002', value: 2001122}, - ], { numberOfRuns: 100 }), - - () => benchmarkCruds('Column ranges - add column', columnRanges, (engine: HyperFormula) => { - engine.addColumns(0, [1, 1]) - engine.setCellContents(adr('A1'), 5) - }, [ - {address: 'AY50', value: 3.47832712968835e+63}, - ], { numberOfRuns: 100 }), - - () => benchmarkCruds('Column ranges - without batch', columnRanges, (engine: HyperFormula) => { - engine.setCellContents(adr('A1'), 1) - engine.setCellContents(adr('A1'), 2) - engine.setCellContents(adr('A1'), 3) - engine.setCellContents(adr('A1'), 4) - engine.setCellContents(adr('A1'), 5) - }, [ - {address: 'AX50', value: 3.47832712968835e+63}, - ], { numberOfRuns: 100 }), - - () => benchmarkCruds('Column ranges - batch', columnRanges, (engine: HyperFormula) => { - engine.batch(() => { - engine.setCellContents(adr('A1'), 1) - engine.setCellContents(adr('A1'), 2) - engine.setCellContents(adr('A1'), 3) - engine.setCellContents(adr('A1'), 4) - engine.setCellContents(adr('A1'), 5) - }) - }, [ - {address: 'AX50', value: 3.47832712968835e+63}, - ], { numberOfRuns: 100 }) - ) - - return result -} diff --git a/test/performance/run-basic-benchmark.ts b/test/performance/run-basic-benchmark.ts deleted file mode 100644 index 7851f54730..0000000000 --- a/test/performance/run-basic-benchmark.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { runBasicBenchmark } from './basic-benchmark' - -(() => { - const result = runBasicBenchmark() - console.table(result.map(e => ({ - name: e.name, - totalTime: e.totalTime - }))) -})() diff --git a/test/performance/run-cruds-benchmark.ts b/test/performance/run-cruds-benchmark.ts deleted file mode 100644 index 563629fbf1..0000000000 --- a/test/performance/run-cruds-benchmark.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { runCrudsBenchmark } from './cruds-benchmark' - -(() => { - const result = runCrudsBenchmark() - console.table(result.map(e => ({ - name: e.name, - totalTime: e.totalTime - }))) -})() diff --git a/test/performance/sheets/05-sheet-t.ts b/test/performance/sheets/05-sheet-t.ts deleted file mode 100644 index 89513c719e..0000000000 --- a/test/performance/sheets/05-sheet-t.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {ExpectedValue} from '../benchmark' -import {RawCellContent, Sheet} from '../../../src' - -export function sheet(rows: number = 10000): Sheet { - const sheet: Sheet = [] - - let prev = 1 - - const prettyRandomString = (chars: number) => [...Array(chars)].map(() => (~~(Math.random() * 36)).toString(36)).join('') - - while (prev <= rows) { - const rowToPush: RawCellContent[] = [ - prettyRandomString(30), - prettyRandomString(30), - `=CONCATENATE(A${prev}, B${prev})`, - ] - - sheet.push(rowToPush) - ++prev - } - return sheet -} - -export function expectedValues(sheet: Sheet): ExpectedValue[] { - return [ - {address: 'C1', value: `${sheet[0][0]}${sheet[0][1]}`}, - {address: 'C1000', value: `${sheet[999][0]}${sheet[999][1]}`}, - {address: 'C10000', value: `${sheet[9999][0]}${sheet[9999][1]}`}, - ] -} diff --git a/test/performance/sheets/09-sheet-a.ts b/test/performance/sheets/09-sheet-a.ts deleted file mode 100644 index f88e1c1cb5..0000000000 --- a/test/performance/sheets/09-sheet-a.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {RawCellContent, Sheet} from '../../../src' -import {ExpectedValue} from '../benchmark' - -export function sheet(rows: number = 10000): Sheet { - const sheet: Sheet = [] - sheet.push(['1', '2', '3', '4', '5']) - - let prev = 1 - - while (prev < rows) { - const rowToPush: RawCellContent[] = [ - `${prev + 1}`, - '3', - `=A${prev}*A${prev}`, - `=C${prev + 1}*A${prev}+B${prev}`, - `=C${prev}-D${prev}*D${prev}+D${prev}*C${prev}/7+C${prev}*C${prev}*3+7*2`, - ] - - sheet.push(rowToPush) - ++prev - } - return sheet -} - -export function expectedValues(_sheet: Sheet): ExpectedValue[] { - return [ - {address: 'A10000', value: 10000}, - {address: 'B10000', value: 3}, - {address: 'C10000', value: 99980001}, - ] -} diff --git a/test/performance/sheets/10-sheet-b.ts b/test/performance/sheets/10-sheet-b.ts deleted file mode 100644 index 5a8bb0d9ff..0000000000 --- a/test/performance/sheets/10-sheet-b.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {ExpectedValue} from '../benchmark' -import {RawCellContent, Sheet} from '../../../src' - -export function sheet(rows: number = 5000): Sheet { - const sheet: Sheet = [] - sheet.push(['1', '2', '3', '0', '0']) - - let prev = 1 - - while (prev < rows) { - const rowToPush: RawCellContent[] = [ - `${prev + 1}`, - '2', - '=3*5', - `=A${prev}+D${prev}`, - `=SUM($A$1:A${prev})`, - ] - - sheet.push(rowToPush) - ++prev - } - return sheet -} - -export function expectedValues(_sheet: Sheet): ExpectedValue[] { - return [ - {address: 'A5000', value: 5000}, - {address: 'B5000', value: 2}, - {address: 'C5000', value: 15}, - {address: 'D5000', value: 12497500}, - {address: 'E5000', value: 12497500}, - ] -} diff --git a/test/performance/sheets/column-ranges.ts b/test/performance/sheets/column-ranges.ts deleted file mode 100644 index b630891faa..0000000000 --- a/test/performance/sheets/column-ranges.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {RawCellContent, Sheet} from '../../../src' -import {columnIndexToLabel, simpleCellAddressToString} from '../../../src/parser/addressRepresentationConverters' - -export function sheet(cols: number = 50): Sheet { - const sheet: Sheet = [] - - const firstRow: RawCellContent[] = [1] - - for (let i = 1; i < cols; ++i) { - const adr = simpleCellAddressToString(() => '', {sheet: 0, row: 0, col: i - 1}, 0) - firstRow.push(`=${adr} + 1`) - } - - sheet.push(firstRow) - - for (let i = 1; i < cols; ++i) { - const rowToPush: RawCellContent[] = [] - - rowToPush.push(...Array(i).fill(null)) - - const startColumn = columnIndexToLabel(i - 1) - - for (let j = i - 1; j < cols - 1; ++j) { - const endColumn = columnIndexToLabel(j) - rowToPush.push(`=SUM(${startColumn}:${endColumn})`) - } - - sheet.push(rowToPush) - } - - return sheet -} diff --git a/test/performance/utils/stats.ts b/test/performance/utils/stats.ts deleted file mode 100644 index 61ed562e99..0000000000 --- a/test/performance/utils/stats.ts +++ /dev/null @@ -1,87 +0,0 @@ -import {HyperFormula} from '../../../src' -import {StatType} from '../../../src/statistics' - -export type Stats = Map - -export enum ExtStatType { - INIT_DATASTRUCTURES = 'INIT_DATASTRUCTURES', - PREPROCESSING = 'PREPROCESSING', - CRUDS_TOTAL = 'CRUDS_TOTAL', -} - -export const EnrichedStatType = {...StatType, ...ExtStatType} -export type EnrichedStatType = StatType | ExtStatType - -export function enrichStatistics(stats: Stats): Stats { - const initDatastructures = (stats.get(EnrichedStatType.GRAPH_BUILD) || 0) - (stats.get(EnrichedStatType.PARSER) || 0) - const preprocessing = (stats.get(EnrichedStatType.GRAPH_BUILD) || 0) + (stats.get(EnrichedStatType.TOP_SORT) || 0) - const enriched = new Map(stats) - enriched.set(EnrichedStatType.INIT_DATASTRUCTURES, initDatastructures) - enriched.set(EnrichedStatType.PREPROCESSING, preprocessing) - return enriched -} - -export function measureCruds(engine: HyperFormula, name: string, func: (engine: HyperFormula) => void): Stats { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - engine._stats.reset() - - const start = Date.now() - func(engine) - const end = Date.now() - - const time = end - start - const actualStats: Stats = engine.getStats() - actualStats.set(EnrichedStatType.CRUDS_TOTAL, time) - - return actualStats -} - -export function statsTreePrint(stats: Stats): void { - const str = - `________________________________________________ -|BUILD_ENGINE_TOTAL: ${stats.get(EnrichedStatType.BUILD_ENGINE_TOTAL) || 0} -| |PREPROCESSING: ${stats.get(EnrichedStatType.PREPROCESSING) || 0} -| | |GRAPH_BUILD: ${stats.get(EnrichedStatType.GRAPH_BUILD) || 0} -| | | |INIT_DATASTRUCTURES: ${stats.get(EnrichedStatType.INIT_DATASTRUCTURES) || 0} -| | | | |BUILD_COLUMN_INDEX: ${stats.get(EnrichedStatType.BUILD_COLUMN_INDEX) || 0} -| | | |PARSER: ${stats.get(EnrichedStatType.PARSER) || 0} -| | |TOP_SORT: ${stats.get(EnrichedStatType.TOP_SORT) || 0} -| |EVALUATION: ${stats.get(EnrichedStatType.EVALUATION) || 0} -| | |VLOOKUP: ${stats.get(EnrichedStatType.VLOOKUP) || 0} -________________________________________________\n` - console.log(str) -} - -export function statsTreePrintCruds(stats: Stats): void { - const str = - `|CRUDS: ${stats.get(EnrichedStatType.CRUDS_TOTAL) || 0} -| |TRANSFORM_ASTS: ${stats.get(EnrichedStatType.TRANSFORM_ASTS) || 0} -| |TRANSFORM_ASTS_POSTPONED: ${stats.get(EnrichedStatType.TRANSFORM_ASTS_POSTPONED) || 0} -| |ADJUSTING_ADDRESS_MAPPING: ${stats.get(EnrichedStatType.ADJUSTING_ADDRESS_MAPPING) || 0} -| |ADJUSTING_MATRIX_MAPPING: ${stats.get(EnrichedStatType.ADJUSTING_ARRAY_MAPPING) || 0} -| |ADJUSTING_RANGES: ${stats.get(EnrichedStatType.ADJUSTING_RANGES) || 0} -| |ADJUSTING_GRAPH: ${stats.get(EnrichedStatType.ADJUSTING_GRAPH) || 0} -| |EVALUATION: ${stats.get(EnrichedStatType.EVALUATION) || 0} -| | |VLOOKUP: ${stats.get(EnrichedStatType.VLOOKUP) || 0} -________________________________________________\n` - console.log(str) -} - -export function reduceStats(stats: Stats[], fn: (_: number[]) => number): Stats { - const averages = new Map() - - for (const key of stats[0].keys()) { - const avg = fn(stats.map((stats) => stats.get(key) || 0)) - averages.set(key, avg) - } - - return averages -} - -export function average(values: number[]): number { - const sum = values.reduce((sum, value) => { - return sum + value - }, 0) - return sum / values.length -} diff --git a/test/performance/utils/utils.ts b/test/performance/utils/utils.ts deleted file mode 100644 index 2bee180ff7..0000000000 --- a/test/performance/utils/utils.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {SimpleCellAddress} from '../../../src' - -export const adr = (stringAddress: string, sheet: number = 0): SimpleCellAddress => { - const result = /^(\$([A-Za-z0-9_]+)\.)?(\$?)([A-Za-z]+)(\$?)([0-9]+)$/.exec(stringAddress)! - const row = Number(result[6]) - 1 - return {sheet: sheet, col: colNumber(result[4]), row: row} -} - -const colNumber = (input: string): number => { - if (input.length === 1) { - return input.toUpperCase().charCodeAt(0) - 65 - } else { - return input.split('').reduce((currentColumn, nextLetter) => { - return currentColumn * 26 + (nextLetter.toUpperCase().charCodeAt(0) - 64) - }, 0) - 1 - } -} diff --git a/test/performance/write-to-file.ts b/test/performance/write-to-file.ts deleted file mode 100644 index 103f1d8e7f..0000000000 --- a/test/performance/write-to-file.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { runBasicBenchmark } from './basic-benchmark' -import { runCrudsBenchmark } from './cruds-benchmark' -import fs = require('fs') - -(() => { - const filename = process.argv[2] - - if (!filename) { - console.log('Usage:\n$ npm run benchmark:write-to-file path/to/file.json') - return - } - - const basicResult = runBasicBenchmark() - const crudsResult = runCrudsBenchmark() - const allBenchmarksResult = [ ...basicResult, ...crudsResult ].map(e => ({ - name: e.name, - totalTime: e.totalTime - })) - - try { - fs.writeFileSync(filename, JSON.stringify(allBenchmarksResult)) - } catch (err) { - console.error(err) - } -})() diff --git a/test/unit/AbsoluteCellRange.spec.ts b/test/unit/AbsoluteCellRange.spec.ts deleted file mode 100644 index e698b237af..0000000000 --- a/test/unit/AbsoluteCellRange.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -import {AbsoluteCellRange, AbsoluteColumnRange, AbsoluteRowRange} from '../../src/AbsoluteCellRange' -import {adr} from './testUtils' -import {SheetsNotEqual} from '../../src/errors' - -describe('AbsoluteCellRange', () => { - describe('#addressInRange', () => { - it('true in simplest case', () => { - const range = AbsoluteCellRange.fromCoordinates(0, 0, 0, 0, 0) - - expect(range.addressInRange(adr('A1'))).toBe(true) - }) - - it('false if different sheets', () => { - const range = AbsoluteCellRange.fromCoordinates(1, 0, 0, 0, 0) - - expect(range.addressInRange(adr('A1'))).toBe(false) - }) - }) - - describe('construct', () => { - it('start should be copied when using static method', () => { - const start = adr('A1') - const range = AbsoluteCellRange.spanFrom(start, 1, 1) - - expect(start).not.toBe(range.start) - }) - - it('ends should be copied whe using constructor', () => { - const start = adr('A1') - const end = adr('B2') - - const range = new AbsoluteCellRange(start, end) - - expect(start).not.toBe(range.start) - expect(end).not.toBe(range.end) - }) - - describe('fromSimpleCellAddresses()', () => { - it('constructs an AbsoluteCellRange when all the coordinates are finite', () => { - const start = { sheet: 0, row: 42, col: 42 } - const end = { sheet: 0, row: 666, col: 666 } - const range = AbsoluteCellRange.fromSimpleCellAddresses(start, end) - - expect(range.start).toEqual(start) - expect(range.end).toEqual(end) - expect(range).toBeInstanceOf(AbsoluteCellRange) - expect(range).not.toBeInstanceOf(AbsoluteColumnRange) - expect(range).not.toBeInstanceOf(AbsoluteRowRange) - }) - - it('constructs an AbsoluteColumnRange when called with end.row = Infinity', () => { - const start = { sheet: 0, row: 0, col: 42 } - const end = { sheet: 0, row: Infinity, col: 43 } - const range = AbsoluteCellRange.fromSimpleCellAddresses(start, end) - - expect(range.start).toEqual(start) - expect(range.end).toEqual(end) - expect(range).toBeInstanceOf(AbsoluteColumnRange) - }) - - it('constructs an AbsoluteRowRange when called with end.col = Infinity', () => { - const start = { sheet: 0, row: 42, col: 0 } - const end = { sheet: 0, row: 43, col: Infinity } - const range = AbsoluteCellRange.fromSimpleCellAddresses(start, end) - - expect(range.start).toEqual(start) - expect(range.end).toEqual(end) - expect(range).toBeInstanceOf(AbsoluteRowRange) - }) - - it('constructs an AbsoluteColumnRange when called with end.row = Infinity, and end.col = Infinity', () => { - const start = { sheet: 0, row: 0, col: 0 } - const end = { sheet: 0, row: Infinity, col: Infinity } - const range = AbsoluteCellRange.fromSimpleCellAddresses(start, end) - - expect(range.start).toEqual(start) - expect(range.end).toEqual(end) - expect(range).toBeInstanceOf(AbsoluteColumnRange) - }) - - it('throws error when trying to construct a cell range with different sheets', () => { - const start = { sheet: 1, row: 42, col: 42 } - const end = { sheet: 2, row: 43, col: 43 } - - expect(() => AbsoluteCellRange.fromSimpleCellAddresses(start, end)).toThrow(new SheetsNotEqual(start.sheet, end.sheet)) - }) - - it('throws error when trying to construct a column range with different sheets', () => { - const start = { sheet: 1, row: 0, col: 42 } - const end = { sheet: 2, row: Infinity, col: 43 } - - expect(() => AbsoluteCellRange.fromSimpleCellAddresses(start, end)).toThrow(new SheetsNotEqual(start.sheet, end.sheet)) - }) - - it('throws error when trying to construct a row range with different sheets', () => { - const start = { sheet: 1, row: 42, col: 0 } - const end = { sheet: 2, row: 43, col: Infinity } - - expect(() => AbsoluteCellRange.fromSimpleCellAddresses(start, end)).toThrow(new SheetsNotEqual(start.sheet, end.sheet)) - }) - }) - }) -}) diff --git a/test/unit/CellContentParser.spec.ts b/test/unit/CellContentParser.spec.ts deleted file mode 100644 index 12c579e2f2..0000000000 --- a/test/unit/CellContentParser.spec.ts +++ /dev/null @@ -1,161 +0,0 @@ -import {ErrorType} from '../../src/Cell' -import {CellContent, CellContentParser} from '../../src/CellContentParser' -import {Config} from '../../src/Config' -import {DateTimeHelper} from '../../src/DateTimeHelper' -import {ErrorMessage} from '../../src/error-message' -import { - CurrencyNumber, - DateNumber, - DateTimeNumber, - PercentNumber, - TimeNumber -} from '../../src/interpreter/InterpreterValue' -import {NumberLiteralHelper} from '../../src/NumberLiteralHelper' - -describe('CellContentParser', () => { - const config = new Config() - const cellContentParser = new CellContentParser(config, new DateTimeHelper(config), new NumberLiteralHelper(config)) - - it('a formula', () => { - expect(cellContentParser.parse('=FOO()')).toEqual(new CellContent.Formula('=FOO()')) - }) - - it('null is empty value', () => { - expect(cellContentParser.parse(null)).toEqual(new CellContent.Empty()) - }) - - it('undefined is empty value', () => { - expect(cellContentParser.parse(undefined)).toEqual(new CellContent.Empty()) - }) - - it('numbers', () => { - expect(cellContentParser.parse('42')).toEqual(new CellContent.Number(42)) - expect(cellContentParser.parse('+42')).toEqual(new CellContent.Number(42)) - expect(cellContentParser.parse(' 42')).toEqual(new CellContent.Number(42)) - expect(cellContentParser.parse('42 ')).toEqual(new CellContent.Number(42)) - expect(cellContentParser.parse('42.13')).toEqual(new CellContent.Number(42.13)) - expect(cellContentParser.parse('-42.13')).toEqual(new CellContent.Number(-42.13)) - expect(cellContentParser.parse('+42.13')).toEqual(new CellContent.Number(42.13)) - expect(cellContentParser.parse('.13')).toEqual(new CellContent.Number(0.13)) - }) - - it('boolean', () => { - expect(cellContentParser.parse('true')).toEqual(new CellContent.Boolean(true)) - expect(cellContentParser.parse('false')).toEqual(new CellContent.Boolean(false)) - expect(cellContentParser.parse('TRUE')).toEqual(new CellContent.Boolean(true)) - expect(cellContentParser.parse('FALSE')).toEqual(new CellContent.Boolean(false)) - expect(cellContentParser.parse('TrUe')).toEqual(new CellContent.Boolean(true)) - expect(cellContentParser.parse('faLSE')).toEqual(new CellContent.Boolean(false)) - }) - - it('numbers with different decimal separators', () => { - const config = new Config({decimalSeparator: ',', functionArgSeparator: ';'}) - const cellContentParser = new CellContentParser(config, new DateTimeHelper(config), new NumberLiteralHelper(config)) - - expect(cellContentParser.parse('42')).toEqual(new CellContent.Number(42)) - expect(cellContentParser.parse('42,13')).toEqual(new CellContent.Number(42.13)) - expect(cellContentParser.parse('-42,13')).toEqual(new CellContent.Number(-42.13)) - expect(cellContentParser.parse('+42,13')).toEqual(new CellContent.Number(42.13)) - expect(cellContentParser.parse(',13')).toEqual(new CellContent.Number(0.13)) - expect(cellContentParser.parse('42.13')).toEqual(new CellContent.String('42.13')) - expect(cellContentParser.parse('12,34,56')).toEqual(new CellContent.String('12,34,56')) - }) - - it('numbers with thousand separators', () => { - const config = new Config({thousandSeparator: ' ', functionArgSeparator: ';'}) - const cellContentParser = new CellContentParser(config, new DateTimeHelper(config), new NumberLiteralHelper(config)) - - expect(cellContentParser.parse('42')).toEqual(new CellContent.Number(42)) - expect(cellContentParser.parse('1234567')).toEqual(new CellContent.Number(1234567)) - expect(cellContentParser.parse('1 234 567')).toEqual(new CellContent.Number(1234567)) - expect(cellContentParser.parse('-1 234 567')).toEqual(new CellContent.Number(-1234567)) - expect(cellContentParser.parse('1234 567')).toEqual(new CellContent.Number(1234567)) - expect(cellContentParser.parse('12 3456 789')).toEqual(new CellContent.Number(123456789)) - expect(cellContentParser.parse('1 234 567.12')).toEqual(new CellContent.Number(1234567.12)) - expect(cellContentParser.parse('12 34 56 7')).toEqual(new CellContent.String('12 34 56 7')) - expect(cellContentParser.parse('1 234.12.12')).toEqual(new CellContent.String('1 234.12.12')) - }) - - it('non-string', () => { - expect(cellContentParser.parse(42)).toEqual(new CellContent.Number(42)) - expect(cellContentParser.parse(true)).toEqual(new CellContent.Boolean(true)) - expect(cellContentParser.parse(null)).toEqual(new CellContent.Empty()) - expect(cellContentParser.parse(undefined)).toEqual(new CellContent.Empty()) - expect(cellContentParser.parse(-0)).toEqual(new CellContent.Number(0)) - expect(cellContentParser.parse(Infinity)).toEqual(new CellContent.Error(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(cellContentParser.parse(-Infinity)).toEqual(new CellContent.Error(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(cellContentParser.parse(NaN)).toEqual(new CellContent.Error(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('string', () => { - expect(cellContentParser.parse('f42')).toEqual(new CellContent.String('f42')) - expect(cellContentParser.parse('42f')).toEqual(new CellContent.String('42f')) - expect(cellContentParser.parse(' =FOO()')).toEqual(new CellContent.String(' =FOO()')) - expect(cellContentParser.parse(' ')).toEqual(new CellContent.String(' ')) - expect(cellContentParser.parse('')).toEqual(new CellContent.String('')) - }) - - it('errors', () => { - expect(cellContentParser.parse('#DIV/0!')).toEqual(new CellContent.Error(ErrorType.DIV_BY_ZERO)) - expect(cellContentParser.parse('#NUM!')).toEqual(new CellContent.Error(ErrorType.NUM)) - expect(cellContentParser.parse('#N/A')).toEqual(new CellContent.Error(ErrorType.NA)) - expect(cellContentParser.parse('#VALUE!')).toEqual(new CellContent.Error(ErrorType.VALUE)) - expect(cellContentParser.parse('#CYCLE!')).toEqual(new CellContent.Error(ErrorType.CYCLE)) - expect(cellContentParser.parse('#NAME?')).toEqual(new CellContent.Error(ErrorType.NAME)) - expect(cellContentParser.parse('#REF!')).toEqual(new CellContent.Error(ErrorType.REF)) - }) - - it('errors are case insensitive', () => { - expect(cellContentParser.parse('#dIv/0!')).toEqual(new CellContent.Error(ErrorType.DIV_BY_ZERO)) - }) - - it('error-like literal is string', () => { - expect(cellContentParser.parse('#FOO!')).toEqual(new CellContent.String('#FOO!')) - }) - - it('date parsing', () => { - expect(cellContentParser.parse('02-02-2020')).toEqual(new CellContent.Number(new DateNumber(43863, 'DD/MM/YYYY'))) - expect(cellContentParser.parse(' 02-02-2020')).toEqual(new CellContent.Number(new DateNumber(43863, 'DD/MM/YYYY'))) - }) - - it('JS Date parsing', () => { - expect(cellContentParser.parse(new Date(1995, 11, 17))).toEqual(new CellContent.Number(new DateNumber(35050, 'Date()'))) - expect(cellContentParser.parse(new Date(1995, 11, 17, 12, 0, 0))).toEqual(new CellContent.Number(new DateTimeNumber(35050.5, 'Date()'))) - expect(cellContentParser.parse(new Date(1899, 11, 30, 6, 0, 0))).toEqual(new CellContent.Number(new TimeNumber(0.25, 'Date()'))) - expect(cellContentParser.parse(new Date(1899, 11, 29))).toEqual(new CellContent.Error(ErrorType.NUM, ErrorMessage.DateBounds)) - }) - - it('starts with \'', () => { - expect(cellContentParser.parse('\'123')).toEqual(new CellContent.String('123')) - expect(cellContentParser.parse('\'=1+1')).toEqual(new CellContent.String('=1+1')) - expect(cellContentParser.parse('\'\'1')).toEqual(new CellContent.String('\'1')) - expect(cellContentParser.parse('\' 1')).toEqual(new CellContent.String(' 1')) - expect(cellContentParser.parse(' \'1')).toEqual(new CellContent.String(' \'1')) - expect(cellContentParser.parse('\'02-02-2020')).toEqual(new CellContent.String('02-02-2020')) - }) - - it('currency parsing', () => { - expect(cellContentParser.parse('1$')).toEqual(new CellContent.Number(new CurrencyNumber(1, '$'))) - expect(cellContentParser.parse('$1')).toEqual(new CellContent.Number(new CurrencyNumber(1, '$'))) - expect(cellContentParser.parse('-1.1e1$')).toEqual(new CellContent.Number(new CurrencyNumber(-11, '$'))) - expect(cellContentParser.parse('$-1.1e1')).toEqual(new CellContent.Number(new CurrencyNumber(-11, '$'))) - expect(cellContentParser.parse(' 1$ ')).toEqual(new CellContent.Number(new CurrencyNumber(1, '$'))) - expect(cellContentParser.parse(' $1 ')).toEqual(new CellContent.Number(new CurrencyNumber(1, '$'))) - expect(cellContentParser.parse('1 $')).toEqual(new CellContent.String('1 $')) - expect(cellContentParser.parse('$ 1')).toEqual(new CellContent.String('$ 1')) - }) - - it('other currency parsing', () => { - expect(cellContentParser.parse('1PLN')).toEqual(new CellContent.String('1PLN')) - const configPLN = new Config({currencySymbol: ['PLN']}) - const cellContentParserPLN = new CellContentParser(configPLN, new DateTimeHelper(configPLN), new NumberLiteralHelper(configPLN)) - expect(cellContentParserPLN.parse('1PLN')).toEqual(new CellContent.Number(new CurrencyNumber(1, 'PLN'))) - }) - - it('percentage parsing', () => { - expect(cellContentParser.parse('100%')).toEqual(new CellContent.Number(new PercentNumber(1))) - expect(cellContentParser.parse('-1.1e3%')).toEqual(new CellContent.Number(new PercentNumber(-11))) - expect(cellContentParser.parse(' 100% ')).toEqual(new CellContent.Number(new PercentNumber(1))) - expect(cellContentParser.parse('100 %')).toEqual(new CellContent.String('100 %')) - }) -}) diff --git a/test/unit/CellValueExporter.spec.ts b/test/unit/CellValueExporter.spec.ts deleted file mode 100644 index ca1daf8cdb..0000000000 --- a/test/unit/CellValueExporter.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import {DetailedCellError, ErrorType, HyperFormula} from '../../src' -import {CellError} from '../../src/Cell' -import {Config} from '../../src/Config' -import { SheetMapping } from '../../src/DependencyGraph' -import {ErrorMessage} from '../../src/error-message' -import {Exporter} from '../../src/Exporter' -import {plPL} from '../../src/i18n/languages' -import {EmptyValue} from '../../src/interpreter/InterpreterValue' -import {LazilyTransformingAstService} from '../../src/LazilyTransformingAstService' -import {NamedExpressions} from '../../src/NamedExpressions' -import {EmptyStatistics} from '../../src/statistics' -import {detailedError} from './testUtils' - -const namedExpressionsMock = {} as NamedExpressions -const sheetMappingMock = {} as SheetMapping -const lazilyTransforminService = new LazilyTransformingAstService(new EmptyStatistics()) - -describe('rounding', () => { - it('no rounding', () => { - const config = new Config({smartRounding: false}) - const cellValueExporter = new Exporter(config, namedExpressionsMock, sheetMappingMock, lazilyTransforminService) - expect(cellValueExporter.exportValue(1.000000000000001)).toBe(1.000000000000001) - expect(cellValueExporter.exportValue(-1.000000000000001)).toBe(-1.000000000000001) - expect(cellValueExporter.exportValue(0.000000000000001)).toBe(0.000000000000001) - expect(cellValueExporter.exportValue(-0.000000000000001)).toBe(-0.000000000000001) - expect(cellValueExporter.exportValue(true)).toBe(true) - expect(cellValueExporter.exportValue(false)).toBe(false) - expect(cellValueExporter.exportValue(1)).toBe(1) - expect(cellValueExporter.exportValue(EmptyValue)).toBe(null) - expect(cellValueExporter.exportValue('abcd')).toBe('abcd') - }) - - it('with rounding', () => { - const config = new Config() - const cellValueExporter = new Exporter(config, namedExpressionsMock, sheetMappingMock, lazilyTransforminService) - expect(cellValueExporter.exportValue(1.000000001)).toBe(1.000000001) - expect(cellValueExporter.exportValue(-1.000000001)).toBe(-1.000000001) - expect(cellValueExporter.exportValue(1.00000000001)).toBe(1) - expect(cellValueExporter.exportValue(-1.00000000001)).toBe(-1) - expect(cellValueExporter.exportValue(0.0000000000001)).toBeCloseTo(0.0000000000001, 13) - expect(cellValueExporter.exportValue(-0.0000000000001)).toBeCloseTo(-0.0000000000001, 13) - expect(cellValueExporter.exportValue(true)).toBe(true) - expect(cellValueExporter.exportValue(false)).toBe(false) - expect(cellValueExporter.exportValue(1)).toBe(1) - expect(cellValueExporter.exportValue(EmptyValue)).toBe(null) - expect(cellValueExporter.exportValue('abcd')).toBe('abcd') - }) -}) - -describe('detailed error', () => { - it('should return detailed errors', () => { - const config = new Config({language: 'enGB'}) - const cellValueExporter = new Exporter(config, namedExpressionsMock, sheetMappingMock, lazilyTransforminService) - - const error = cellValueExporter.exportValue(new CellError(ErrorType.VALUE)) as DetailedCellError - expect(error).toEqualError(detailedError(ErrorType.VALUE)) - expect(error.value).toEqual('#VALUE!') - }) - - it('should return detailed errors with translation', () => { - HyperFormula.registerLanguage('plPL', plPL) - const config = new Config({language: 'plPL'}) - const cellValueExporter = new Exporter(config, namedExpressionsMock, sheetMappingMock, lazilyTransforminService) - - const error = cellValueExporter.exportValue(new CellError(ErrorType.VALUE)) as DetailedCellError - expect(error).toEqualError(detailedError(ErrorType.VALUE, undefined, config)) - expect(error.value).toEqual('#ARG!') - }) - - it('pretty print', () => { - expect(`${detailedError(ErrorType.REF, ErrorMessage.DateBounds)}`).toEqual('#REF!') - }) -}) diff --git a/test/unit/ColumnsSpan.spec.ts b/test/unit/ColumnsSpan.spec.ts deleted file mode 100644 index f6db13a947..0000000000 --- a/test/unit/ColumnsSpan.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import {ColumnsSpan} from '../../src/Span' - -describe('ColumnsSpan', () => { - it('raise error when starting column is less than 0', () => { - expect(() => { - new ColumnsSpan(0, -1, 0) - }).toThrowError('Starting column cant be less than 0') - }) - - it('raise error when column end before column start', () => { - expect(() => { - new ColumnsSpan(0, 1, 0) - }).toThrowError('Column span cant end before start') - }) - - it('#fromNumberOfColumns', () => { - const span = ColumnsSpan.fromNumberOfColumns(0, 42, 2) - - expect(span).toEqual(new ColumnsSpan(0, 42, 43)) - }) - - it('#numberOfColumns for one column', () => { - const span = new ColumnsSpan(0, 42, 42) - - expect(span.numberOfColumns).toBe(1) - }) - - it('#numberOfColumns for more than one column', () => { - const span = new ColumnsSpan(0, 42, 45) - - expect(span.numberOfColumns).toBe(4) - }) - - it('#columns iterates over column numbers', () => { - const span = new ColumnsSpan(0, 42, 45) - - expect(Array.from(span.columns())).toEqual([42, 43, 44, 45]) - }) - - it('#intersect with span from other sheet', () => { - const span1 = new ColumnsSpan(0, 42, 45) - const span2 = new ColumnsSpan(1, 43, 45) - - expect(() => { - span1.intersect(span2) - }).toThrowError("Can't intersect spans from different sheets") - }) - - it('#intersect with span overlapping at right', () => { - const span1 = new ColumnsSpan(0, 42, 45) - const span2 = new ColumnsSpan(0, 43, 46) - - expect(span1.intersect(span2)).toEqual(new ColumnsSpan(0, 43, 45)) - }) - - it('#intersect with span whole after', () => { - const span1 = new ColumnsSpan(0, 42, 45) - const span2 = new ColumnsSpan(0, 46, 49) - - expect(span1.intersect(span2)).toBe(null) - }) - - it('#intersect with span overlapping at left', () => { - const span1 = new ColumnsSpan(0, 42, 45) - const span2 = new ColumnsSpan(0, 40, 44) - - expect(span1.intersect(span2)).toEqual(new ColumnsSpan(0, 42, 44)) - }) - - it('#intersect with span whole before', () => { - const span1 = new ColumnsSpan(0, 42, 45) - const span2 = new ColumnsSpan(0, 39, 41) - - expect(span1.intersect(span2)).toBe(null) - }) - - it('#intersect with span included', () => { - const span1 = new ColumnsSpan(0, 42, 45) - const span2 = new ColumnsSpan(0, 43, 44) - - expect(span1.intersect(span2)).toEqual(span2) - }) - - it('#intersect with span outside', () => { - const span1 = new ColumnsSpan(0, 42, 45) - const span2 = new ColumnsSpan(0, 40, 47) - - expect(span1.intersect(span2)).toEqual(span1) - }) - - it('#firstColumn when one column', () => { - const span1 = new ColumnsSpan(0, 42, 42) - - expect(span1.firstColumn()).toEqual(span1) - }) - - it('#firstColumn when more columns', () => { - const span1 = new ColumnsSpan(0, 42, 44) - - expect(span1.firstColumn()).toEqual(new ColumnsSpan(0, 42, 42)) - }) -}) diff --git a/test/unit/RowsSpan.spec.ts b/test/unit/RowsSpan.spec.ts deleted file mode 100644 index 881fdd06b6..0000000000 --- a/test/unit/RowsSpan.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import {RowsSpan} from '../../src/Span' - -describe('RowsSpan', () => { - it('raise error when starting row is less than 0', () => { - expect(() => { - new RowsSpan(0, -1, 0) - }).toThrowError('Starting row cant be less than 0') - }) - - it('raise error when row end before row start', () => { - expect(() => { - new RowsSpan(0, 1, 0) - }).toThrowError('Row span cant end before start') - }) - - it('#fromNumberOfRows', () => { - const span = RowsSpan.fromNumberOfRows(0, 42, 2) - - expect(span).toEqual(new RowsSpan(0, 42, 43)) - }) - - it('#numberOfRows for one row', () => { - const span = new RowsSpan(0, 42, 42) - - expect(span.numberOfRows).toBe(1) - }) - - it('#numberOfRows for more than one row', () => { - const span = new RowsSpan(0, 42, 45) - - expect(span.numberOfRows).toBe(4) - }) - - it('#rows iterates over row numbers', () => { - const span = new RowsSpan(0, 42, 45) - - expect(Array.from(span.rows())).toEqual([42, 43, 44, 45]) - }) - - it('#intersect with span from other sheet', () => { - const span1 = new RowsSpan(0, 42, 45) - const span2 = new RowsSpan(1, 43, 45) - - expect(() => { - span1.intersect(span2) - }).toThrowError("Can't intersect spans from different sheets") - }) - - it('#intersect with span overlapping at right', () => { - const span1 = new RowsSpan(0, 42, 45) - const span2 = new RowsSpan(0, 43, 46) - - expect(span1.intersect(span2)).toEqual(new RowsSpan(0, 43, 45)) - }) - - it('#intersect with span whole after', () => { - const span1 = new RowsSpan(0, 42, 45) - const span2 = new RowsSpan(0, 46, 49) - - expect(span1.intersect(span2)).toBe(null) - }) - - it('#intersect with span overlapping at left', () => { - const span1 = new RowsSpan(0, 42, 45) - const span2 = new RowsSpan(0, 40, 44) - - expect(span1.intersect(span2)).toEqual(new RowsSpan(0, 42, 44)) - }) - - it('#intersect with span whole before', () => { - const span1 = new RowsSpan(0, 42, 45) - const span2 = new RowsSpan(0, 39, 41) - - expect(span1.intersect(span2)).toBe(null) - }) - - it('#intersect with span included', () => { - const span1 = new RowsSpan(0, 42, 45) - const span2 = new RowsSpan(0, 43, 44) - - expect(span1.intersect(span2)).toEqual(span2) - }) - - it('#intersect with span outside', () => { - const span1 = new RowsSpan(0, 42, 45) - const span2 = new RowsSpan(0, 40, 47) - - expect(span1.intersect(span2)).toEqual(span1) - }) - - it('#firstRow when one row', () => { - const span1 = new RowsSpan(0, 42, 42) - - expect(span1.firstRow()).toEqual(span1) - }) - - it('#firstRow when more rows', () => { - const span1 = new RowsSpan(0, 42, 44) - - expect(span1.firstRow()).toEqual(new RowsSpan(0, 42, 42)) - }) -}) diff --git a/test/unit/_setupFiles/babel.js b/test/unit/_setupFiles/babel.js deleted file mode 100644 index 8e8cbfbbde..0000000000 --- a/test/unit/_setupFiles/babel.js +++ /dev/null @@ -1,3 +0,0 @@ -require('@babel/register')({ - 'extensions': ['.js', '.ts'] -}); diff --git a/test/unit/_setupFiles/bootstrap.ts b/test/unit/_setupFiles/bootstrap.ts deleted file mode 100644 index 572cd7a5be..0000000000 --- a/test/unit/_setupFiles/bootstrap.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * This script file presents you the opportunity of running some code immediately - * after the test framework has been installed in the environment. - */ -import {HyperFormula} from '../../../src' -import {Config} from '../../../src/Config' -import {enGB} from '../../../src/i18n/languages' -import * as plugins from '../../../src/interpreter/plugin' -import {unregisterAllLanguages} from '../testUtils' -import {toContainEqualMatcher, toEqualErrorMatcher, toMatchObjectMatcher} from './matchers' - -Config.defaultConfig = Object.assign({}, Config.defaultConfig, { - functionPlugins: [], - useStats: true, - licenseKey: 'gpl-v3', -}) - -const jestPresent = (() => { - try { - expect([{a: 0}]).toContainEqual({a: 0}) - return true - } catch (e) { - return false - } -})() - -beforeEach(() => { - if (!jestPresent) { - (jasmine as any).setDefaultSpyStrategy((and: any) => and.callThrough()) - } - - unregisterAllLanguages() - - const defaultLanguage = Config.defaultConfig.language - - HyperFormula.registerLanguage(defaultLanguage, enGB) - - HyperFormula.unregisterAllFunctions() - - for (const pluginName of Object.getOwnPropertyNames(plugins)) { - if (!pluginName.startsWith('_')) { - HyperFormula.registerFunctionPlugin(plugins[pluginName as keyof typeof plugins]) - } - } -}) - -beforeAll(() => { - if (!jestPresent) { - (jasmine as any).addMatchers({ - ...toContainEqualMatcher, - ...toMatchObjectMatcher, - ...toEqualErrorMatcher, - }) - } else { - if (global.gc) { - global.gc() - } - } -}) diff --git a/test/unit/_setupFiles/globalSetup.ts b/test/unit/_setupFiles/globalSetup.ts deleted file mode 100644 index 792f64c289..0000000000 --- a/test/unit/_setupFiles/globalSetup.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * This script file presents you the opportunity of running some code immediately - * before the test framework has been installed in the environment. - */ -// eslint-disable-next-line @typescript-eslint/no-var-requires -const htConfig = require('./../../../ht.config') - -export default function() { - // Extract all HF constants to the process environment namespance. - // So the HT_RELEASE_DATE consts and other will be accessible while - // testing the lib. - Object.keys(htConfig).forEach((key) => { - process.env[key] = htConfig[key] - }) -} diff --git a/test/unit/_setupFiles/jest/bootstrap.ts b/test/unit/_setupFiles/jest/bootstrap.ts deleted file mode 100644 index f8f8f9d29a..0000000000 --- a/test/unit/_setupFiles/jest/bootstrap.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {toEqualError} from './toEqualError' - -beforeAll(() => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - // eslint-disable-next-line no-global-assign - spyOn = jest.spyOn - expect.extend(toEqualError) -}) diff --git a/test/unit/_setupFiles/jest/toEqualError.ts b/test/unit/_setupFiles/jest/toEqualError.ts deleted file mode 100644 index 80f274cfc2..0000000000 --- a/test/unit/_setupFiles/jest/toEqualError.ts +++ /dev/null @@ -1,29 +0,0 @@ -type CustomMatcherResult = jest.CustomMatcherResult -type ExpectExtendMap = jest.ExpectExtendMap - -declare global { - namespace jest { - interface Matchers { - toEqualError(expected: any): CustomMatcherResult, - } - } -} - -export const toEqualError: ExpectExtendMap = { - toEqualError(received: any, expected: any): CustomMatcherResult { - let result = false - - if (typeof received === 'object' && typeof expected === 'object' && received.message != null && expected.message != null && received.message.includes(expected.message)) { - result = this.equals( - {...received, message: undefined, root: undefined, address: undefined}, - {...expected, message: undefined, root: undefined, address: undefined} - ) - } else { - result = this.equals(received, expected) - } - return { - pass: result, - message: () => (result ? '' : `Expected ${JSON.stringify(received, null, 2)} to match ${JSON.stringify(expected, null, 2)}.`) - } - } -} diff --git a/test/unit/_setupFiles/jsdom.js b/test/unit/_setupFiles/jsdom.js deleted file mode 100644 index 5ab4d33496..0000000000 --- a/test/unit/_setupFiles/jsdom.js +++ /dev/null @@ -1,7 +0,0 @@ -import {JSDOM} from 'jsdom' - -const dom = new JSDOM(''); - -global.document = dom.window.document; -global.window = dom.window; -global.navigator = dom.window.navigator; diff --git a/test/unit/_setupFiles/matchers/index.ts b/test/unit/_setupFiles/matchers/index.ts deleted file mode 100644 index 4435383da1..0000000000 --- a/test/unit/_setupFiles/matchers/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export {toContainEqualMatcher} from './toContainEqual' -export {toMatchObjectMatcher} from './toMatchObject' -export {toEqualErrorMatcher} from './toEqualError' diff --git a/test/unit/_setupFiles/matchers/toContainEqual.ts b/test/unit/_setupFiles/matchers/toContainEqual.ts deleted file mode 100644 index 7277bb9226..0000000000 --- a/test/unit/_setupFiles/matchers/toContainEqual.ts +++ /dev/null @@ -1,25 +0,0 @@ -type CustomMatcher = jasmine.CustomMatcher -type CustomMatcherFactories = jasmine.CustomMatcherFactories -type CustomMatcherResult = jasmine.CustomMatcherResult -type MatchersUtil = jasmine.MatchersUtil - -declare global { - namespace jasmine { - interface Matchers { - toContainEqual(expected: object, expectationFailOutput?: string): boolean, - } - } -} - -export const toContainEqualMatcher: CustomMatcherFactories = { - toContainEqual: function(util: MatchersUtil): CustomMatcher { - return { - compare: function(actual: any[], expected: any): CustomMatcherResult { - return { - pass: util.equals(actual, jasmine.arrayContaining([expected])), - message: '' - } - }, - } - } -} diff --git a/test/unit/_setupFiles/matchers/toEqualError.ts b/test/unit/_setupFiles/matchers/toEqualError.ts deleted file mode 100644 index 6c0b87bb56..0000000000 --- a/test/unit/_setupFiles/matchers/toEqualError.ts +++ /dev/null @@ -1,34 +0,0 @@ -type CustomMatcher = jasmine.CustomMatcher -type CustomMatcherFactories = jasmine.CustomMatcherFactories -type CustomMatcherResult = jasmine.CustomMatcherResult -type MatchersUtil = jasmine.MatchersUtil - -declare global { - namespace jasmine { - interface Matchers { - toEqualError(expected: any, expectationFailOutput?: string): boolean, - } - } -} - -export const toEqualErrorMatcher: CustomMatcherFactories = { - toEqualError: function(util: MatchersUtil): CustomMatcher { - return { - compare: function(received: any, expected: any): CustomMatcherResult { - let result - if (typeof received === 'object' && typeof expected === 'object' && received.message != null && expected.message != null && received.message.includes(expected.message)) { - result = util.equals( - {...received, message: undefined, root: undefined, address: undefined}, - {...expected, message: undefined, root: undefined, address: undefined} - ) - } else { - result = util.equals(received, expected) - } - return { - pass: result, - message: result ? '' : `Expected ${JSON.stringify(received, null, 2)} to match ${JSON.stringify(expected, null, 2)}.` - } - }, - } - } -} diff --git a/test/unit/_setupFiles/matchers/toMatchObject.ts b/test/unit/_setupFiles/matchers/toMatchObject.ts deleted file mode 100644 index c8353988ca..0000000000 --- a/test/unit/_setupFiles/matchers/toMatchObject.ts +++ /dev/null @@ -1,25 +0,0 @@ -type CustomMatcher = jasmine.CustomMatcher -type CustomMatcherFactories = jasmine.CustomMatcherFactories -type CustomMatcherResult = jasmine.CustomMatcherResult -type MatchersUtil = jasmine.MatchersUtil - -declare global { - namespace jasmine { - interface Matchers { - toMatchObject(expected: object, expectationFailOutput?: string): boolean, - } - } -} - -export const toMatchObjectMatcher: CustomMatcherFactories = { - toMatchObject: function(util: MatchersUtil): CustomMatcher { - return { - compare: function(actual: never, expected: never): CustomMatcherResult { - return { - pass: util.equals(actual, jasmine.objectContaining(expected)), - message: '' - } - }, - } - } -} diff --git a/test/unit/address-mapping.spec.ts b/test/unit/address-mapping.spec.ts deleted file mode 100644 index 496c714d5d..0000000000 --- a/test/unit/address-mapping.spec.ts +++ /dev/null @@ -1,714 +0,0 @@ -import {AddressMapping, DenseStrategy, EmptyCellVertex, SparseStrategy, ValueCellVertex} from '../../src/DependencyGraph' -import { - AlwaysDense, - AlwaysSparse, - DenseSparseChooseBasedOnThreshold -} from '../../src/DependencyGraph/AddressMapping/ChooseAddressMappingPolicy' -import {findBoundaries} from '../../src/Sheet' -import {ColumnsSpan, RowsSpan} from '../../src/Span' -import {adr} from './testUtils' - -const sharedExamples = (builder: (width: number, height: number) => AddressMapping) => { - it('simple set', () => { - const mapping = builder(1, 1) - const vertex = new ValueCellVertex(42, 42) - const address = adr('A1') - - mapping.setCell(address, vertex) - - expect(mapping.getCell(address)).toBe(vertex) - }) - - it('set and using different reference when get', () => { - const mapping = builder(1, 1) - const vertex = new ValueCellVertex(42, 42) - - mapping.setCell(adr('A1'), vertex) - - expect(mapping.getCell(adr('A1'))).toBe(vertex) - }) - - it("get when there's even no column", () => { - const mapping = builder(1, 1) - - expect(mapping.getCell(adr('A1'))).toBe(undefined) - }) - - it('get when there was already something in that column', () => { - const mapping = builder(1, 2) - - mapping.setCell(adr('A2'), new ValueCellVertex(42, 42)) - - expect(mapping.getCell(adr('A1'))).toBe(undefined) - }) - - it('get when asking for out of the row bound cell', () => { - const mapping = builder(1, 1) - - expect(mapping.getCell(adr('A2'))).toBe(undefined) - }) - - it('get all entries', () => { - const mapping = builder(1, 2) - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - - const results = [] - for (const [simpleCellAddress, cellVertex] of mapping.sheetEntries(0)) { - results.push([ - simpleCellAddress.sheet, - simpleCellAddress.row, - simpleCellAddress.col, - String(cellVertex.getCellValue()), - ]) - } - - expect(results).toEqual([ - [0, 0, 0, String(42)], - [0, 1, 0, String(43)], - ]) - }) - - it('get all entries - from rows span', () => { - const mapping = builder(3, 3) - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const [simpleCellAddress, cellVertex] of mapping.entriesFromRowsSpan(new RowsSpan(0, 1, 2))) { - results.push([ - simpleCellAddress.sheet, - simpleCellAddress.row, - simpleCellAddress.col, - String(cellVertex.getCellValue()), - ]) - } - - expect(results).toEqual([ - [0, 1, 0, String(43)], - [0, 2, 0, String(44)], - [0, 1, 1, String(46)], - [0, 2, 1, String(47)], - [0, 1, 2, String(49)], - [0, 2, 2, String(50)], - ]) - }) - - it('get all entries - from columns span', () => { - const mapping = builder(3, 3) - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const [simpleCellAddress, cellVertex] of mapping.entriesFromColumnsSpan(new ColumnsSpan(0, 1, 2))) { - results.push([ - simpleCellAddress.sheet, - simpleCellAddress.row, - simpleCellAddress.col, - String(cellVertex.getCellValue()), - ]) - } - - expect(results).toEqual([ - [0, 0, 1, String(45)], - [0, 1, 1, String(46)], - [0, 2, 1, String(47)], - [0, 0, 2, String(48)], - [0, 1, 2, String(49)], - [0, 2, 2, String(50)], - ]) - }) - - it("set when there's already something in that column", () => { - const mapping = builder(1, 2) - const vertex0 = new ValueCellVertex(42, 42) - const vertex1 = new ValueCellVertex(42, 42) - mapping.setCell(adr('A1'), vertex0) - - mapping.setCell(adr('A2'), vertex1) - - expect(mapping.getCell(adr('A1'))).toBe(vertex0) - expect(mapping.getCell(adr('A2'))).toBe(vertex1) - }) - - it('set overrides old value', () => { - const mapping = builder(1, 1) - const vertex0 = new ValueCellVertex(42, 42) - const vertex1 = new ValueCellVertex(42, 42) - mapping.setCell(adr('A1'), vertex0) - - mapping.setCell(adr('A1'), vertex1) - - expect(mapping.getCell(adr('A1'))).toBe(vertex1) - }) - - it("has when there's even no column", () => { - const mapping = builder(1, 1) - - expect(mapping.has(adr('A1'))).toBe(false) - }) - - it("has when there's even no row", () => { - const mapping = builder(1, 1) - - expect(mapping.has(adr('A3'))).toBe(false) - }) - - it('has when there was already something in that column', () => { - const mapping = builder(1, 2) - - mapping.setCell(adr('A2'), new ValueCellVertex(42, 42)) - - expect(mapping.has(adr('A1'))).toBe(false) - }) - - it('has when there is a value', () => { - const mapping = builder(1, 1) - - mapping.setCell(adr('A1'), new ValueCellVertex(42, 42)) - - expect(mapping.has(adr('A1'))).toBe(true) - }) - - it('addRows in the beginning of a mapping', () => { - const mapping = builder(1, 1) - - mapping.setCell(adr('A1'), new ValueCellVertex(42, 42)) - - mapping.addRows(0, 0, 1) - - expect(mapping.getCell(adr('A1'))).toBe(undefined) - expect(mapping.getCell(adr('A2'))).toEqual(new ValueCellVertex(42, 42)) - expect(mapping.getSheetHeight(0)).toEqual(2) - }) - - it('addRows in the middle of a mapping', () => { - const mapping = builder(1, 2) - - mapping.setCell(adr('A1'), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2'), new ValueCellVertex(43, 43)) - - mapping.addRows(0, 1, 1) - - expect(mapping.getCell(adr('A1'))).toEqual(new ValueCellVertex(42, 42)) - expect(mapping.getCell(adr('A2'))).toBe(undefined) - expect(mapping.getCell(adr('A3'))).toEqual(new ValueCellVertex(43, 43)) - expect(mapping.getSheetHeight(0)).toEqual(3) - }) - - it('addRows in the end of a mapping', () => { - const mapping = builder(1, 1) - - mapping.setCell(adr('A1'), new ValueCellVertex(42, 42)) - - mapping.addRows(0, 1, 1) - - expect(mapping.getCell(adr('A1'))).toEqual(new ValueCellVertex(42, 42)) - expect(mapping.getCell(adr('A2'))).toBe(undefined) - expect(mapping.getSheetHeight(0)).toEqual(2) - }) - - it('addRows more than one row', () => { - const mapping = builder(1, 2) - - mapping.setCell(adr('A1'), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2'), new ValueCellVertex(43, 43)) - - mapping.addRows(0, 1, 3) - - expect(mapping.getCell(adr('A1'))).toEqual(new ValueCellVertex(42, 42)) - expect(mapping.getCell(adr('A2'))).toBe(undefined) - expect(mapping.getCell(adr('A3'))).toBe(undefined) - expect(mapping.getCell(adr('A4'))).toBe(undefined) - expect(mapping.getCell(adr('A5'))).toEqual(new ValueCellVertex(43, 43)) - expect(mapping.getSheetHeight(0)).toEqual(5) - }) - - it('addRows when more than one column present', () => { - const mapping = builder(2, 2) - - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - mapping.addRows(0, 1, 1) - - expect(mapping.getCell(adr('A1'))).toEqual(new ValueCellVertex(11, 11)) - expect(mapping.getCell(adr('B1'))).toEqual(new ValueCellVertex(12, 12)) - expect(mapping.getCell(adr('A2'))).toBe(undefined) - expect(mapping.getCell(adr('B2'))).toBe(undefined) - expect(mapping.getCell(adr('A3'))).toEqual(new ValueCellVertex(21, 21)) - expect(mapping.getCell(adr('B3'))).toEqual(new ValueCellVertex(22, 22)) - expect(mapping.getSheetHeight(0)).toEqual(3) - }) - - it('removeRows - one row', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) // to remove - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) // to remove - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - expect(mapping.getSheetHeight(0)).toBe(2) - mapping.removeRows(new RowsSpan(0, 0, 0)) - expect(mapping.getSheetHeight(0)).toBe(1) - expect(mapping.getCellValue(adr('A1'))).toBe(21) - expect(mapping.getCellValue(adr('B1'))).toBe(22) - }) - - it('removeRows - more than one row', () => { - const mapping = builder(2, 4) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) // to - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) // re - mapping.setCell(adr('A3'), new ValueCellVertex(31, 31)) // mo - mapping.setCell(adr('B3'), new ValueCellVertex(32, 32)) // ve - mapping.setCell(adr('A4'), new ValueCellVertex(41, 41)) - mapping.setCell(adr('B4'), new ValueCellVertex(42, 42)) - - expect(mapping.getSheetHeight(0)).toBe(4) - mapping.removeRows(new RowsSpan(0, 1, 2)) - expect(mapping.getSheetHeight(0)).toBe(2) - expect(mapping.getCellValue(adr('A1'))).toBe(11) - expect(mapping.getCellValue(adr('A2'))).toBe(41) - }) - - it('removeRows - remove more rows thant mapping size', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - expect(mapping.getSheetHeight(0)).toBe(2) - mapping.removeRows(new RowsSpan(0, 0, 5)) - expect(mapping.getSheetHeight(0)).toBe(0) - expect(mapping.has(adr('A1'))).toBe(false) - }) - - it('removeRows - remove more cols than size, but still something left', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - mapping.removeRows(new RowsSpan(0, 1, 5)) - - expect(mapping.getSheetHeight(0)).toBe(1) - expect(mapping.has(adr('A1'))).toBe(true) - expect(mapping.has(adr('A2'))).toBe(false) - }) - - it('removeRows - sometimes nothing is removed', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - mapping.removeRows(new RowsSpan(0, 2, 3)) - - expect(mapping.getSheetHeight(0)).toBe(2) - expect(mapping.has(adr('A1'))).toBe(true) - expect(mapping.has(adr('A2'))).toBe(true) - }) - - it('removeColumns - more than one col', () => { - const mapping = builder(4, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('A2'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('B1'), new ValueCellVertex(21, 21)) // to - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) // re - mapping.setCell(adr('C1'), new ValueCellVertex(31, 31)) // mo - mapping.setCell(adr('C2'), new ValueCellVertex(32, 32)) // ve - mapping.setCell(adr('D1'), new ValueCellVertex(41, 41)) - mapping.setCell(adr('D2'), new ValueCellVertex(42, 42)) - - expect(mapping.getSheetWidth(0)).toBe(4) - mapping.removeColumns(new ColumnsSpan(0, 1, 2)) - expect(mapping.getSheetWidth(0)).toBe(2) - expect(mapping.getCellValue(adr('A1'))).toBe(11) - expect(mapping.getCellValue(adr('B1'))).toBe(41) - }) - - it('removeColumns - remove more cols thant mapping size', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - expect(mapping.getSheetHeight(0)).toBe(2) - mapping.removeColumns(new ColumnsSpan(0, 0, 5)) - expect(mapping.getSheetWidth(0)).toBe(0) - expect(mapping.has(adr('A1'))).toBe(false) - }) - - it('removeColumns - remove more cols than size, but still something left', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - mapping.removeColumns(new ColumnsSpan(0, 1, 5)) - - expect(mapping.getSheetWidth(0)).toBe(1) - expect(mapping.has(adr('A1'))).toBe(true) - expect(mapping.has(adr('B1'))).toBe(false) - }) - - it('removeColumns - sometimes nothing is removed', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(11, 11)) - mapping.setCell(adr('B1'), new ValueCellVertex(12, 12)) - mapping.setCell(adr('A2'), new ValueCellVertex(21, 21)) - mapping.setCell(adr('B2'), new ValueCellVertex(22, 22)) - - mapping.removeColumns(new ColumnsSpan(0, 2, 3)) - - expect(mapping.getSheetWidth(0)).toBe(2) - expect(mapping.has(adr('A1'))).toBe(true) - expect(mapping.has(adr('B1'))).toBe(true) - }) - - it('should expand columns when adding cell', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('C1'), new EmptyCellVertex()) - expect(mapping.getSheetWidth(0)).toBe(3) - }) - - it('should expand rows when adding cell', () => { - const mapping = builder(2, 2) - mapping.setCell(adr('A3'), new EmptyCellVertex()) - expect(mapping.getSheetHeight(0)).toBe(3) - }) - - it('should move cell from source to destination', () => { - const mapping = builder(1, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(42, 42)) - - mapping.moveCell(adr('A1'), adr('A2')) - - expect(mapping.has(adr('A1'))).toEqual(false) - expect(mapping.has(adr('A2'))).toEqual(true) - }) - - it('should throw error when trying to move not existing vertex', () => { - const mapping = builder(1, 2) - - expect(() => mapping.moveCell(adr('A1'), adr('A2'))).toThrowError('Cannot move cell. No cell with such address.') - }) - - it('should throw error when trying to move vertex onto occupied place', () => { - const mapping = builder(1, 2) - mapping.setCell(adr('A1'), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2'), new ValueCellVertex(42, 42)) - - expect(() => mapping.moveCell(adr('A1'), adr('A2'))).toThrowError('Cannot move cell. Destination already occupied.') - }) - - it('should move vertices between sheets', () => { - const mapping = builder(1, 2) - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - - mapping.moveCell(adr('A1', 0), adr('A2', 1)) - - expect(mapping.has(adr('A1', 0))).toEqual(false) - expect(mapping.has(adr('A2', 1))).toEqual(true) - }) - - it('should throw error when trying to move vertices in non-existing sheet', () => { - const mapping = builder(1, 2) - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - - expect(() => mapping.moveCell(adr('A1', 3), adr('A2', 3))).toThrowError('Sheet not initialized.') - }) - - it('entriesFromColumnsSpan returns the same result regardless of the strategy', () => { - const denseMapping = new AddressMapping(new AlwaysDense()) - denseMapping.addSheetWithStrategy(0, new DenseStrategy(5, 5)) - - const sparseMapping = new AddressMapping(new AlwaysSparse()) - sparseMapping.addSheetWithStrategy(0, new SparseStrategy(5, 5)) - - const mappingsAndResults: { mapping: AddressMapping, results: String[][] }[] = [ - { - mapping: denseMapping, - results: [], - }, - { - mapping: sparseMapping, - results: [], - } - ] - - mappingsAndResults.forEach((item) => { - item.mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - item.mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - item.mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - item.mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - item.mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - item.mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - item.mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - item.mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - item.mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - }) - - mappingsAndResults.forEach((item) => { - for (const [simpleCellAddress, cellVertex] of item.mapping.entriesFromColumnsSpan(new ColumnsSpan(0, 1, 2))) { - item.results.push([ - String(simpleCellAddress.sheet), - String(simpleCellAddress.row), - String(simpleCellAddress.col), - String(cellVertex.getCellValue()), - ]) - } - }) - - expect(mappingsAndResults[0].results).toEqual(mappingsAndResults[1].results) - }) -} - -describe('SparseStrategy', () => { - sharedExamples((maxCol: number, maxRow: number) => { - const mapping = new AddressMapping(new AlwaysSparse()) - mapping.addSheetWithStrategy(0, new SparseStrategy(maxCol, maxRow)) - mapping.addSheetWithStrategy(1, new SparseStrategy(maxCol, maxRow)) - return mapping - }) - - it('returns maximum row/col for simplest case', () => { - const mapping = new AddressMapping(new AlwaysSparse()) - mapping.addSheetWithStrategy(0, new SparseStrategy(4, 16)) - - mapping.setCell(adr('D16'), new ValueCellVertex(42, 42)) - - expect(mapping.getSheetHeight(0)).toEqual(16) - expect(mapping.getSheetWidth(0)).toEqual(4) - }) - - it('get all vertices', () => { - const mapping = new AddressMapping(new AlwaysSparse()) - const sparseStrategy = new SparseStrategy(3, 3) - mapping.addSheetWithStrategy(0, sparseStrategy) - - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const cellVertex of sparseStrategy.vertices()) { - results.push(String(cellVertex.getCellValue())) - } - - expect(results).toEqual([ - '42', '43', '44', '45', '46', '47', '48', '49', '50' - ]) - }) - - it('get all vertices - from column', () => { - const mapping = new AddressMapping(new AlwaysSparse()) - const sparseStrategy = new SparseStrategy(3, 3) - mapping.addSheetWithStrategy(0, sparseStrategy) - - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const cellVertex of sparseStrategy.verticesFromColumn(2)) { - results.push(String(cellVertex.getCellValue())) - } - - const outOfRangeResults = [] - for (const cellVertex of sparseStrategy.verticesFromColumn(5)) { - outOfRangeResults.push(String(cellVertex.getCellValue())) - } - - expect(results).toEqual(['48', '49', '50']) - expect(outOfRangeResults).toEqual([]) - }) - - it('get all vertices - from row', () => { - const mapping = new AddressMapping(new AlwaysSparse()) - const sparseStrategy = new SparseStrategy(3, 3) - mapping.addSheetWithStrategy(0, sparseStrategy) - - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const cellVertex of sparseStrategy.verticesFromRow(1)) { - results.push(String(cellVertex.getCellValue())) - } - - const outOfRangeResults = [] - for (const cellVertex of sparseStrategy.verticesFromRow(5)) { - outOfRangeResults.push(String(cellVertex.getCellValue())) - } - - expect(results).toEqual(['43', '46', '49']) - expect(outOfRangeResults).toEqual([]) - }) -}) - -describe('DenseStrategy', () => { - sharedExamples((maxCol, maxRow) => { - const mapping = new AddressMapping(new AlwaysDense()) - mapping.addSheetWithStrategy(0, new DenseStrategy(maxCol, maxRow)) - mapping.addSheetWithStrategy(1, new DenseStrategy(maxCol, maxRow)) - return mapping - }) - - it('returns maximum row/col for simplest case', () => { - const mapping = new AddressMapping(new AlwaysDense()) - mapping.addSheetWithStrategy(0, new DenseStrategy(1, 2)) - - expect(mapping.getSheetHeight(0)).toEqual(2) - expect(mapping.getSheetWidth(0)).toEqual(1) - }) - - it('get all vertices', () => { - const mapping = new AddressMapping(new AlwaysDense()) - const denseStratgey = new DenseStrategy(3, 3) - mapping.addSheetWithStrategy(0, denseStratgey) - - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const cellVertex of denseStratgey.vertices()) { - results.push(String(cellVertex.getCellValue())) - } - - expect(results).toEqual([ - '42', '45', '48', '43', '46', '49', '44', '47', '50' - ]) - }) - - it('get all vertices - from column', () => { - const mapping = new AddressMapping(new AlwaysDense()) - const denseStratgey = new DenseStrategy(3, 3) - mapping.addSheetWithStrategy(0, denseStratgey) - - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const cellVertex of denseStratgey.verticesFromColumn(2)) { - results.push(String(cellVertex.getCellValue())) - } - - const outOfRangeResults = [] - for (const cellVertex of denseStratgey.verticesFromColumn(5)) { - outOfRangeResults.push(String(cellVertex.getCellValue())) - } - - expect(results).toEqual(['48', '49', '50']) - expect(outOfRangeResults).toEqual([]) - }) - - it('get all vertices - from row', () => { - const mapping = new AddressMapping(new AlwaysDense()) - const denseStratgey = new DenseStrategy(3, 3) - mapping.addSheetWithStrategy(0, denseStratgey) - - mapping.setCell(adr('A1', 0), new ValueCellVertex(42, 42)) - mapping.setCell(adr('A2', 0), new ValueCellVertex(43, 43)) - mapping.setCell(adr('A3', 0), new ValueCellVertex(44, 44)) - mapping.setCell(adr('B1', 0), new ValueCellVertex(45, 45)) - mapping.setCell(adr('B2', 0), new ValueCellVertex(46, 46)) - mapping.setCell(adr('B3', 0), new ValueCellVertex(47, 47)) - mapping.setCell(adr('C1', 0), new ValueCellVertex(48, 48)) - mapping.setCell(adr('C2', 0), new ValueCellVertex(49, 49)) - mapping.setCell(adr('C3', 0), new ValueCellVertex(50, 50)) - - const results = [] - for (const cellVertex of denseStratgey.verticesFromRow(1)) { - results.push(String(cellVertex.getCellValue())) - } - - const outOfRangeResults = [] - for (const cellVertex of denseStratgey.verticesFromRow(5)) { - outOfRangeResults.push(String(cellVertex.getCellValue())) - } - - expect(results).toEqual(['43', '46', '49']) - expect(outOfRangeResults).toEqual([]) - }) -}) - -describe('AddressMapping', () => { - it('#buildAddresMapping - when sparse matrix', () => { - const addressMapping = new AddressMapping(new DenseSparseChooseBasedOnThreshold(0.8)) - const sheet = [ - [null, null, null], - [null, null, '1'], - ] - addressMapping.addSheetAndSetStrategyBasedOnBoundaries(0, findBoundaries(sheet)) - - expect(addressMapping.getStrategyForSheetOrThrow(0)).toBeInstanceOf(SparseStrategy) - }) - - it('#buildAddresMapping - when dense matrix', () => { - const addressMapping = new AddressMapping(new DenseSparseChooseBasedOnThreshold(0.8)) - const sheet = [ - ['1', '1'], - ['1', '1'], - ] - addressMapping.addSheetAndSetStrategyBasedOnBoundaries(0, findBoundaries(sheet)) - - expect(addressMapping.getStrategyForSheetOrThrow(0)).toBeInstanceOf(DenseStrategy) - }) -}) diff --git a/test/unit/address-representation-converters.spec.ts b/test/unit/address-representation-converters.spec.ts deleted file mode 100644 index a0731eddb8..0000000000 --- a/test/unit/address-representation-converters.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import {simpleCellRange} from '../../src/AbsoluteCellRange' -import {simpleCellAddress} from '../../src/Cell' -import {Maybe} from '../../src/Maybe' -import { - simpleCellAddressFromString, - simpleCellAddressToString, - simpleCellRangeFromString, - simpleCellRangeToString -} from '../../src/parser' -import {adr} from './testUtils' - -describe('simpleCellAddressFromString', () => { - const sheetMappingFunction = (name: string): Maybe => { - const index = ['Sheet1', 'Sheet2', 'Sheet3'].indexOf(name) - return index > 0 ? index : undefined - } - - it('should return a simple cell address when called with a valid string address', () => { - expect(simpleCellAddressFromString(sheetMappingFunction, 'A1', 0)).toEqual(adr('A1')) - expect(simpleCellAddressFromString(sheetMappingFunction, 'AY7', 0)).toEqual(simpleCellAddress(0, 50, 6)) - }) - - it('should return undefined when sheet does not exist', () => { - expect(simpleCellAddressFromString(sheetMappingFunction, 'Sheet4!A1', 0)).toBeUndefined() - }) - - it('should return address with context sheet when string address does not contain a sheet name', () => { - expect(simpleCellAddressFromString(sheetMappingFunction, 'A1', 1)).toEqual(adr('A1', 1)) - }) - - it('should return a valid address when called with a valid sheet name', () => { - expect(simpleCellAddressFromString(sheetMappingFunction, 'Sheet2!A1', 1)).toEqual(adr('A1', 1)) - }) - - it('should return address with sheet number from sheet mapping regardless of context sheet parameter', () => { - expect(simpleCellAddressFromString(sheetMappingFunction, 'Sheet3!A1', 1)).toEqual(adr('A1', 2)) - }) -}) - -describe('simpleCellRangeFromString', () => { - const sheetMappingFunction = (name: string): Maybe => { - const index = ['Sheet1', 'Sheet2', 'Sheet3'].indexOf(name) - return index > 0 ? index : undefined - } - - it('should not accept invalid ranges', () => { - expect(simpleCellRangeFromString(sheetMappingFunction, 'A1', 0)).toEqual(undefined) - expect(simpleCellRangeFromString(sheetMappingFunction, 'A1:B1:C1', 0)).toEqual(undefined) - }) - - it('should return undefined when the Sheet4 does not exist', () => { - expect(simpleCellRangeFromString(sheetMappingFunction, 'Sheet4!A1:A2', 0)).toEqual(undefined) - }) - - it('should return address with overridden sheet', () => { - expect(simpleCellRangeFromString(sheetMappingFunction, 'A1:A2', 1)).toEqual(simpleCellRange(adr('A1', 1), adr('A2', 1))) - }) - - it('should return address with sheet number from sheet mapping', () => { - expect(simpleCellRangeFromString(sheetMappingFunction, 'Sheet2!A1:A2', 1)).toEqual(simpleCellRange(adr('A1', 1), adr('A2', 1))) - }) - - it('should return address with sheet number from sheet mapping for both start and end', () => { - expect(simpleCellRangeFromString(sheetMappingFunction, 'Sheet2!A1:Sheet2!A2', 1)).toEqual(simpleCellRange(adr('A1', 1), adr('A2', 1))) - }) - - it('should return address with sheet number from sheet mapping regardless of override parameter', () => { - expect(simpleCellRangeFromString(sheetMappingFunction, 'Sheet3!A1:Sheet3!A2', 1)).toEqual(simpleCellRange(adr('A1', 2), adr('A2', 2))) - }) - - it('should not accept distinct sheets', () => { - expect(simpleCellRangeFromString(sheetMappingFunction, 'A1:Sheet3!A2', 1)).toEqual(undefined) - expect(simpleCellRangeFromString(sheetMappingFunction, 'Sheet2!A1:Sheet3!A2', 1)).toEqual(undefined) - }) -}) - -describe('simpleCellAddressToString', () => { - const sheetIndexMappingFunction = (index: number): Maybe => { - return ['Sheet1', 'Sheet2', 'Sheet3', '~`!@#$%^&*()_-+_=/|?{}[]"', "Sheet'With'Quotes"][index] - } - - it('should return string representation', () => { - expect(simpleCellAddressToString(sheetIndexMappingFunction, adr('A1'), 0)).toEqual('A1') - expect(simpleCellAddressToString(sheetIndexMappingFunction, simpleCellAddress(0, 50, 6), 0)).toEqual('AY7') - }) - - it('should return string representation with sheet name', () => { - expect(simpleCellAddressToString(sheetIndexMappingFunction, adr('A1'), 1)).toEqual('Sheet1!A1') - }) - - it('should quote sheet names with special characters', () => { - expect(simpleCellAddressToString(sheetIndexMappingFunction, adr('A1', 3), 1)).toEqual("'~`!@#$%^&*()_-+_=/|?{}[]\"'!A1") - }) - - it('should escape quote in quotes', () => { - expect(simpleCellAddressToString(sheetIndexMappingFunction, adr('A1', 4), 1)).toEqual("'Sheet''With''Quotes'!A1") - }) - - it('should return undefined', () => { - expect(simpleCellAddressToString(sheetIndexMappingFunction, adr('A1', 42), 42)).toBeUndefined() - expect(simpleCellAddressToString(sheetIndexMappingFunction, adr('A1', 42), 1)).toBeUndefined() - }) -}) - -describe('simpleCellRangeToString', () => { - const sheetIndexMappingFunction = (index: number): Maybe => { - return ['Sheet1', 'Sheet2', 'Sheet3'][index] - } - - it('should return string representation', () => { - expect(simpleCellRangeToString(sheetIndexMappingFunction, simpleCellRange(adr('A1'), adr('A2')), 0)).toEqual('A1:A2') - }) - - it('should return string representation with sheet name', () => { - expect(simpleCellRangeToString(sheetIndexMappingFunction, simpleCellRange(adr('A1'), adr('A2')), 1)).toEqual('Sheet1!A1:A2') - }) - - it('should return undefined when refering nonexistent sheet', () => { - expect(simpleCellRangeToString(sheetIndexMappingFunction, simpleCellRange(adr('A1', 42), adr('A2', 42)), 42)).toBeUndefined() - expect(simpleCellRangeToString(sheetIndexMappingFunction, simpleCellRange(adr('A1', 42), adr('A2', 42)), 1)).toBeUndefined() - }) -}) diff --git a/test/unit/arrays-integration.spec.ts b/test/unit/arrays-integration.spec.ts deleted file mode 100644 index 09aad73441..0000000000 --- a/test/unit/arrays-integration.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {HyperFormula} from '../../src' -import {adr} from './testUtils' - -describe('integration test', () => { - it('should work', () => { - const engine = HyperFormula.buildFromSheets({ - 'Output': [['=INDEX(LookupRange,MATCH(1,(Lookup!A1:A8<=Inputs!A1)*(Lookup!B1:B8>=Inputs!A1)*(Lookup!C1:C8=Inputs!B1), 0), 4)']], - 'Inputs': [[23, 'B']], - 'Lookup': [ - [11, 15, 'A', 66], - [11, 15, 'B', 77], - [16, 20, 'A', 88], - [16, 20, 'B', 99], - [21, 25, 'A', 110], - [21, 25, 'B', 121], - [26, 30, 'A', 132], - [26, 30, 'B', 143], - ] - }, {useArrayArithmetic: true}) //flag that enables ArrayFormula() everywhere - - engine.addNamedExpression('LookupRange', '=Lookup!$A$1:Lookup!$D$8') - - expect(engine.getCellValue(adr('A1'))).toEqual(121) - - engine.setCellContents(adr('B1', engine.getSheetId('Inputs')), 'A') - - expect(engine.getCellValue(adr('A1'))).toEqual(110) - }) -}) diff --git a/test/unit/arrays.spec.ts b/test/unit/arrays.spec.ts deleted file mode 100644 index 71d29cc94f..0000000000 --- a/test/unit/arrays.spec.ts +++ /dev/null @@ -1,537 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {ArraySize} from '../../src/ArraySize' -import {ArrayFormulaVertex, ValueCellVertex} from '../../src/DependencyGraph' -import {ErrorMessage} from '../../src/error-message' -import {adr, detailedError, detailedErrorWithOrigin, expectVerticesOfTypes, noSpace} from './testUtils' - -describe('without arrayformula, with useArrayArithmetic flag', () => { - it('unary op, scalar ret', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=SUM(-A1:C1)']], {useArrayArithmetic: true}) - expect(engine.getCellValue(adr('A2'))).toEqual(-6) - }) - - it('unary op, array ret', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=-A1:C1']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3], [-1, -2, -3]]) - }) - - it('binary op, scalar ret', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], ['=SUM(2*A1:C1+A2:C2)']], {useArrayArithmetic: true}) - expect(engine.getCellValue(adr('A3'))).toEqual(27) - }) - - it('binary op, array ret', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], ['=2*A1:C1+A2:C2']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3], [4, 5, 6], [6, 9, 12]]) - }) - - it('binary op, array ret, concat', () => { - const engine = HyperFormula.buildFromArray([['a', 'b', 'c'], ['d', 'e', 'f'], ['=A1:C1&A2:C2']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([['a', 'b', 'c'], ['d', 'e', 'f'], ['ad', 'be', 'cf']]) - }) - - it('index', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=INDEX(2*A1:C1+3,1,1)']], {useArrayArithmetic: true}) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - }) - - it('binary op + index', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ['=INDEX(A1:C2+A1:B3,1,1)', '=INDEX(A1:C2+A1:B3,1,2)', '=INDEX(A1:C2+A1:B3,1,3)'], - ['=INDEX(A1:C2+A1:B3,2,1)', '=INDEX(A1:C2+A1:B3,2,2)', '=INDEX(A1:C2+A1:B3,2,3)'], - ['=INDEX(A1:C2+A1:B3,3,1)', '=INDEX(A1:C2+A1:B3,3,2)', '=INDEX(A1:C2+A1:B3,3,3)'], - ], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual( - [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - [2, 4, detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!C4')], - [8, 10, detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!C5')], - [detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!A6'), detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!B6'), detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!C6')]]) - }) - - it('match', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(10,2*A2:E2)'], - [1, 2, 3, 4, 5], - ], {useArrayArithmetic: true}) - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) -}) - -describe('without arrayformula, without useArrayArithmetic flag', () => { - it('unary op', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [undefined, undefined, undefined, '=SUM(-A1:C1)']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('D2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('binary op', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [undefined, undefined, undefined, '=SUM(2*A1:C1+A2:C2)']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('D3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('index', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [undefined, undefined, undefined, '=INDEX(2*A1:C1+3,1,1)']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('D2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('binary op + index', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ['=INDEX(A1:C2+A1:B3,1,1)', '=INDEX(A1:C2+A1:B3,1,2)', '=INDEX(A1:C2+A1:B3,1,3)'], - ['=INDEX(A1:C2+A1:B3,2,1)', '=INDEX(A1:C2+A1:B3,2,2)', '=INDEX(A1:C2+A1:B3,2,3)'], - ['=INDEX(A1:C2+A1:B3,3,1)', '=INDEX(A1:C2+A1:B3,3,2)', '=INDEX(A1:C2+A1:B3,3,3)'], - ], {useArrayArithmetic: false}) - expect(engine.getSheetValues(0)).toEqual( - [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - [detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!A4', ErrorMessage.ScalarExpected), detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!B4', ErrorMessage.ScalarExpected), detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!C4', ErrorMessage.ScalarExpected)], - [detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!A5', ErrorMessage.ScalarExpected), detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!B5', ErrorMessage.ScalarExpected), detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!C5', ErrorMessage.ScalarExpected)], - [detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!A6', ErrorMessage.ScalarExpected), detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!B6', ErrorMessage.ScalarExpected), detailedErrorWithOrigin(ErrorType.VALUE, 'Sheet1!C6', ErrorMessage.ScalarExpected)] - ]) - }) - - it('match', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(10,2*B1:F1)', 1, 2, 3, 4, 5], - ], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) -}) - -describe('with arrayformula, without useArrayArithmetic flag', () => { - it('unary op', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=ARRAYFORMULA(SUM(-A1:C1))']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A2'))).toEqual(-6) - }) - - it('unary op #2', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=SUM(ARRAYFORMULA(-A1:C1))']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A2'))).toEqual(-6) - }) - - it('binary op', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], ['=ARRAYFORMULA(SUM(2*A1:C1+A2:C2))']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A3'))).toEqual(27) - }) - - it('binary op #2', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], ['=SUM(ARRAYFORMULA(2*A1:C1+A2:C2))']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A3'))).toEqual(27) - }) - - it('index', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=ARRAYFORMULA(INDEX(2*A1:C1+3,1,1))']], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - }) - - it('binary op + index', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ['=ARRAYFORMULA(INDEX(A1:C2+A1:B3,1,1))', '=ARRAYFORMULA(INDEX(A1:C2+A1:B3,1,2))', '=ARRAYFORMULA(INDEX(A1:C2+A1:B3,1,3))'], - ['=ARRAYFORMULA(INDEX(A1:C2+A1:B3,2,1))', '=ARRAYFORMULA(INDEX(A1:C2+A1:B3,2,2))', '=ARRAYFORMULA(INDEX(A1:C2+A1:B3,2,3))'], - ['=ARRAYFORMULA(INDEX(A1:C2+A1:B3,3,1))', '=ARRAYFORMULA(INDEX(A1:C2+A1:B3,3,2))', '=ARRAYFORMULA(INDEX(A1:C2+A1:B3,3,3))'], - ], {useArrayArithmetic: false}) - expect(engine.getSheetValues(0)).toEqual( - [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - [2, 4, detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!C4')], - [8, 10, detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!C5')], - [detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!A6'), detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!B6'), detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!C6')]]) - }) - - it('match', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAYFORMULA(MATCH(10,2*A2:E2))'], - [1, 2, 3, 4, 5], - ], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) -}) - -describe('coercion of array to scalar', () => { - it('actual range', () => { - const engine = HyperFormula.buildFromArray([[0, 2, 3, '=SIN(A1:C1)']]) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('array + function #1', () => { - const engine = HyperFormula.buildFromArray([[0, 2, 3], ['=SIN(ARRAYFORMULA(2*A1:C1))']]) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('inline array + function #2', () => { - const engine = HyperFormula.buildFromArray([['=SIN({0,2,3})']]) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('array + binary op #1', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=ARRAYFORMULA(2*A1:C1)+ARRAYFORMULA(2*A1:C1)']]) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3], [4]]) - }) - - it('inline array + binary op #2', () => { - const engine = HyperFormula.buildFromArray([['={1,2,3}+{1,2,3}']]) - expect(engine.getSheetValues(0)).toEqual([[2]]) - }) - - it('array + unary op #1', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=-ARRAYFORMULA(2*A1:C1)']]) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3], [-2]]) - }) - - it('inline array + unary op #2', () => { - const engine = HyperFormula.buildFromArray([['=-{1,2,3}']]) - expect(engine.getSheetValues(0)).toEqual([[-1]]) - }) -}) - -describe('range interpolation', () => { - it('with function', () => { - const engine = HyperFormula.buildFromArray([[0, 1, 2], ['=EXP(A1:C1)']]) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('with binary op', () => { - const engine = HyperFormula.buildFromArray([[0, 1, 2], [undefined, '=A1:C1+A1:C1']]) - expect(engine.getCellValue(adr('B2'))).toEqual(2) - }) - - it('with unary op', () => { - const engine = HyperFormula.buildFromArray([[0, 1, 2], [undefined, '=-A1:C1']]) - expect(engine.getCellValue(adr('B2'))).toEqual(-1) - }) - - it('columns', () => { - const engine = HyperFormula.buildFromArray([[0], [1, '=-A1:A3'], [2]]) - expect(engine.getCellValue(adr('B2'))).toEqual(-1) - }) - - it('too many rows', () => { - const engine = HyperFormula.buildFromArray([[0, 1, 2], [4, 5, 6], [undefined, '=-A1:C2']]) - expect(engine.getCellValue(adr('B3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('different sheets', () => { - const engine = HyperFormula.buildFromSheets({Sheet1: [[0, 1, 2]], Sheet2: [['=-Sheet1!A1:C1']]}) - expect(engine.getCellValue(adr('A1', 1))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) -}) - -describe('inline arrays', () => { - describe('should be expanded into multiple cells', () => { - it('simple 2D array', () => { - const engine = HyperFormula.buildFromArray([['={1,2;3,4}']]) - expect(engine.getSheetValues(0)).toEqual([[1, 2], [3, 4]]) - }) - - it('nested arrays', () => { - const engine = HyperFormula.buildFromArray([['={1,{2,3},4;{5;6},{7,8;9,10},{11;12};13,{14,15},16}']]) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3, 4], [5, 7, 8, 11], [6, 9, 10, 12], [13, 14, 15, 16]]) - }) - - it('nested arrays with operators', () => { - const engine = HyperFormula.buildFromArray([['=ARRAYFORMULA({1,{2,3}+{0,0},4;{5;6},2*{7,8;9,10},-{11;12};13,{14,15},16})']]) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3, 4], [5, 14, 16, -11], [6, 18, 20, -12], [13, 14, 15, 16]]) - }) - }) - - it('size mismatch should result in an error', () => { - const engine = HyperFormula.buildFromArray([['={1,2;3}']]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SizeMismatch)) - }) - - it('should work inside a function', () => { - const hyperFormula: HyperFormula = HyperFormula.buildFromArray( - [['=SUM({1, 2})']], - {licenseKey: 'gpl-v3'}, - ) - expect(hyperFormula.getCellValue({row: 0, col: 0, sheet: 0})).toBe(3) - }) - - it('should not update the value when referenced cells change', () => { - const hyperFormula: HyperFormula = HyperFormula.buildFromArray( - [[1, '={A1}']], - {licenseKey: 'gpl-v3'}, - ) - expect(hyperFormula.getCellValue({row: 0, col: 1, sheet: 0})).toBe(1) - hyperFormula.setCellContents({row: 0, col: 0, sheet: 0}, 42) - expect(hyperFormula.getCellValue({row: 0, col: 1, sheet: 0})).toBe(1) - }) -}) - -describe('vectorization', () => { - it('1 arg function row', () => { - const engine = HyperFormula.buildFromArray([['=ABS({-2,-1,1,2})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[2, 1, 1, 2]]) - }) - - it('1 arg function column', () => { - const engine = HyperFormula.buildFromArray([['=ABS({2;-2})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[2], [2]]) - }) - - it('1 arg function square', () => { - const engine = HyperFormula.buildFromArray([['=ABS({1,2;-1,-2})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[1, 2], [1, 2]]) - }) - - it('1 arg function no flag - should cast to scalar', () => { - const engine = HyperFormula.buildFromArray([['=ABS({-2,-1,1,2})']], {useArrayArithmetic: false}) - expect(engine.getSheetValues(0)).toEqual([[2]]) - }) - - it('multi arg function', () => { - const engine = HyperFormula.buildFromArray([['=DATE({1,2},1,1)']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[367, 732]]) - }) - - it('multi arg function #2', () => { - const engine = HyperFormula.buildFromArray([['=DATE({1,2},{1,2},{1,2})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[367, 764]]) - }) - - it('multi arg function #3', () => { - const engine = HyperFormula.buildFromArray([['=DATE({1,2},{1;2},{1})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[367, 732], [398, 763]]) - }) - - it('multi arg function #4', () => { - const engine = HyperFormula.buildFromArray([['=DATE({1,2},{1,2,3},{1})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[367, 763, detailedError(ErrorType.VALUE, ErrorMessage.InvalidDate)]]) - }) - - it('mixed types', () => { - const engine = HyperFormula.buildFromArray([['=ZTEST({1,2,1},{2;3})']], {useArrayArithmetic: true}) - const val = engine.getSheetValues(0) - expect(val.length).toEqual(2) - expect(val[0].length).toEqual(1) - expect(val[1].length).toEqual(1) - }) - - it('no vectorization here #1', () => { - const engine = HyperFormula.buildFromArray([['=SUM({1,2,1},{2;3})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[9]]) - }) - - it('no vectorization here #2', () => { - const engine = HyperFormula.buildFromArray([['=AND({TRUE(),FALSE()},{TRUE();FALSE()})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[false]]) - }) - - it('vectorize with defaults', () => { - const engine = HyperFormula.buildFromArray([['=IF({TRUE(),FALSE()},{1;2;3}, {2;3})']], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[1, 2], [2, 3], [3, false]]) - }) - - it('should work with switch', () => { - const engine = HyperFormula.buildFromArray([ - ['=SWITCH({1,2,3},1,2,3,4,5)'] - ], {useArrayArithmetic: true}) - expect(engine.getSheetValues(0)).toEqual([[2, 5, 4]]) - }) -}) - -describe('build from array', () => { - it('should create engine with array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=-A1:B2'], - [3, 4], - ], {useArrayArithmetic: true}) - - expect(engine.getSheetValues(0)).toEqual([ - [1, 2, -1, -2], - [3, 4, -3, -4], - ]) - }) - - it('should be enough to specify only corner of an array', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(D1:E2)'], - ], {useArrayArithmetic: true}) - - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, ArrayFormulaVertex], - [ArrayFormulaVertex, ArrayFormulaVertex], - ]) - }) - - it('should be separate arrays', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(D1:E2)', '=TRANSPOSE(D1:E2)'], - ['=TRANSPOSE(D1:E2)', '=TRANSPOSE(D1:E2)'], - ], {useArrayArithmetic: true}) - - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, ArrayFormulaVertex, undefined], - [ArrayFormulaVertex, ArrayFormulaVertex, ArrayFormulaVertex], - [undefined, ArrayFormulaVertex, ArrayFormulaVertex], - ]) - expect(engine.arrayMapping.arrayMapping.size).toEqual(4) - }) - - it('should REF last array', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(D1:E2)', '=TRANSPOSE(D1:E2)', null, 1, 2], - ['=TRANSPOSE(D1:E2)', null, null, 1, 2], - ], {useArrayArithmetic: true}) - - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, ArrayFormulaVertex, ArrayFormulaVertex], - [ArrayFormulaVertex, ArrayFormulaVertex, ArrayFormulaVertex], - [undefined, undefined], - ]) - expect(engine.getSheetValues(0)).toEqual([ - [noSpace(), 1, 1, 1, 2], - [noSpace(), 2, 2, 1, 2], - ]) - expect(engine.arrayMapping.arrayMapping.size).toEqual(3) - }) - - it('array should work with different types of data', () => { - const engine = HyperFormula.buildFromArray([ - [1, 'foo', '=TRANSPOSE(A1:B2)'], - [true, '=SUM(A1)'], - ], {useArrayArithmetic: true}) - - expect(engine.getSheetValues(0)).toEqual([ - [1, 'foo', 1, true], - [true, 1, 'foo', 1], - ]) - }) - - it('should make REF array if no space', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C1:D2', 2], - [3, 4], - ], {useArrayArithmetic: true}) - - expect(engine.getSheetValues(0)).toEqual([ - [noSpace(), 2], - [3, 4], - ]) - }) - - it('should not shrink array if empty vertex', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C1:D2', null], - [null, null] - ], {useArrayArithmetic: true}) - - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, ArrayFormulaVertex], - [ArrayFormulaVertex, ArrayFormulaVertex], - ]) - - }) - - it('should shrink to one vertex if there is more content colliding with array', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C1:D2', null], - [1, null] - ], {useArrayArithmetic: true}) - - expect(engine.arrayMapping.getArrayByCorner(adr('A1'))?.array.size).toEqual(ArraySize.error()) - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, undefined], - [ValueCellVertex, undefined], - ]) - }) - - it('DependencyGraph changes should be empty after building fresh engine', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C1:D2', null], - [1, null] - ], {useArrayArithmetic: true}) - - expect(engine.dependencyGraph.getAndClearContentChanges().isEmpty()).toEqual(true) - }) -}) - -describe('column ranges', () => { - it('arithmetic should work for column range', () => { - const engine = HyperFormula.buildFromArray([ - ['=2*(B:B)', 1], - [null, 2], - ], {useArrayArithmetic: true}) - - expect(engine.getSheetValues(0)).toEqual([[2, 1], [4, 2]]) - }) - - it('arithmetic should work for row range', () => { - const engine = HyperFormula.buildFromArray([ - ['=2*(2:2)', null], - [1, 2], - ], {useArrayArithmetic: true}) - - expect(engine.getSheetValues(0)).toEqual([[2, 4], [1, 2]]) - }) - - it('arithmetic for shifted column range -- error', () => { - const engine = HyperFormula.buildFromArray([ - [null, 1], - ['=2*(B:B)', 2], - ], {useArrayArithmetic: true}) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - }) - - it('arithmetic for shifted row range -- error', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=2*(2:2)'], - [1, 2], - ], {useArrayArithmetic: true}) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - }) - - it('sumproduct test', () => { - const engine = HyperFormula.buildFromArray([ - [1, 1, 3, '=SUMPRODUCT((A:A=1)*(B:B=1), C:C)'], - [1, 2, 3], - [3, 1, 3], - ], {useArrayArithmetic: true} - ) - - expect(engine.getCellValue(adr('D1'))).toEqual(3) - }) - - it('should handle array shrinking when dependent is a value cell', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ['=TRANSPOSE(A1:B2)'], - ], {useArrayArithmetic: true}) - - expect(engine.getCellValue(adr('A3'))).toBe(1) - expect(engine.getCellValue(adr('A4'))).toBe(2) - expect(engine.getCellValue(adr('B3'))).toBe(3) - expect(engine.getCellValue(adr('B4'))).toBe(4) - - engine.setCellContents(adr('B3'), 'obstructing value') - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - }) - - it('should correctly set address mapping for scalar formula', () => { - const engine = HyperFormula.buildFromArray([ - ['=1+1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(2) - expect(engine.addressMapping.getCell(adr('A1'))).toBeDefined() - expect(engine.addressMapping.getCell(adr('B1'))).toBeUndefined() - }) -}) diff --git a/test/unit/build-engine.spec.ts b/test/unit/build-engine.spec.ts deleted file mode 100644 index 0e16c94480..0000000000 --- a/test/unit/build-engine.spec.ts +++ /dev/null @@ -1,114 +0,0 @@ -import {HyperFormula} from '../../src' -import {plPL} from '../../src/i18n/languages' -import {adr} from './testUtils' - -describe('Building empty engine', () => { - it('works', () => { - const engine = HyperFormula.buildEmpty() - expect(engine).toBeInstanceOf(HyperFormula) - }) - - it('accepts config params', () => { - const config = {dateFormats: ['MM']} - const engine = HyperFormula.buildEmpty(config) - expect(engine.getConfig().dateFormats[0]).toBe('MM') - }) -}) - -describe('Building engine from arrays', () => { - it('works', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [], - Sheet2: [], - }) - - expect(engine).toBeInstanceOf(HyperFormula) - }) - - it('#buildFromSheet adds default sheet Sheet1', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.getAllSheetsDimensions()).toEqual({'Sheet1': {'height': 0, 'width': 0}}) - }) - - it('#buildFromSheet adds default sheet Sheet1, in different languages', () => { - HyperFormula.registerLanguage('plPL', plPL) - const engine = HyperFormula.buildFromArray([], {language: 'plPL'}) - - expect(engine.getAllSheetsDimensions()).toEqual({'Arkusz1': {'height': 0, 'width': 0}}) - }) - - it('#buildFromSheets accepts config', () => { - const config = {dateFormats: ['MM']} - const engine = HyperFormula.buildFromSheets({ - Sheet1: [], - Sheet2: [], - }, config) - - expect(engine.getConfig().dateFormats[0]).toBe('MM') - }) - - it('#buildFromSheet accepts config', () => { - const config = {dateFormats: ['MM']} - const engine = HyperFormula.buildFromArray([], config) - - expect(engine.getConfig().dateFormats[0]).toBe('MM') - }) - - it('should allow to create sheets with a delay', () => { - const sheetName = 'Sheet2' - const engine = HyperFormula.buildFromArray([[`=${sheetName}!A1`]]) - - engine.addSheet(sheetName) - const sheetId = engine.getSheetId(sheetName)! - engine.setSheetContent(sheetId, [['1']]) - engine.rebuildAndRecalculate() - - expect(engine.getCellValue(adr('A1', sheetId))).toBe(1) - expect(engine.getCellValue(adr('A1', 0))).toBe(1) - }) - - it('corrupted sheet definition', () => { - expect(() => { - HyperFormula.buildFromArray([ - [0, 1], - [2, 3], - null, // broken sheet - [6, 7] - ] as any) - }).toThrowError('Invalid arguments, expected an array of arrays.') - }) -}) - -describe('named expressions', () => { - it('buildEmpty', () => { - const engine = HyperFormula.buildEmpty({}, [{name: 'FALSE', expression: false}]) - engine.addSheet('sheet') - engine.setSheetContent(0, [['=FALSE']]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('buildFromArray', () => { - const engine = HyperFormula.buildFromArray([['=FALSE']], {}, [{name: 'FALSE', expression: false}]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('buildFromSheets', () => { - const engine = HyperFormula.buildFromSheets({sheet: [['=FALSE']]}, {}, [{name: 'FALSE', expression: false}]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('buildFromArray + scope', () => { - const engine = HyperFormula.buildFromArray([['=FALSE']], {}, [{name: 'FALSE', expression: false, scope: 0}]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('buildFromSheets + scope', () => { - const engine = HyperFormula.buildFromSheets({sheet: [['=FALSE']]}, {}, [{ - name: 'FALSE', - expression: false, - scope: 0 - }]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) -}) diff --git a/test/unit/cache-order.spec.ts b/test/unit/cache-order.spec.ts deleted file mode 100644 index 88b66b7f32..0000000000 --- a/test/unit/cache-order.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {HyperFormula} from '../../src' -import {adr} from './testUtils' - -describe('cache order invariance', () => { - it('should evaluate properly #1', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=SUM(A1,B1:C1)', '=SUM(B1:C1)']]) - expect(engine.getCellValue(adr('A2'))).toEqual(6) - expect(engine.getCellValue(adr('B2'))).toEqual(5) - }) - - it('should evaluate properly #2', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=SUM(B1:C1,A1)', '=SUM(B1:C1)']]) - expect(engine.getCellValue(adr('A2'))).toEqual(6) - expect(engine.getCellValue(adr('B2'))).toEqual(5) - }) - - it('should evaluate properly #3', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=SUM(B1:C1)', '=SUM(A1,B1:C1)']]) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - expect(engine.getCellValue(adr('B2'))).toEqual(6) - }) - - it('should evaluate properly #4', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], ['=SUM(B1:C1)', '=SUM(B1:C1,A1)']]) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - expect(engine.getCellValue(adr('B2'))).toEqual(6) - }) -}) diff --git a/test/unit/column-index.spec.ts b/test/unit/column-index.spec.ts deleted file mode 100644 index b82f81fe5e..0000000000 --- a/test/unit/column-index.spec.ts +++ /dev/null @@ -1,844 +0,0 @@ -import {deepStrictEqual} from 'assert' -import {HyperFormula} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {CellError, ErrorType} from '../../src' -import {Config} from '../../src/Config' -import {DependencyGraph} from '../../src/DependencyGraph' -import {AddRowsTransformer} from '../../src/dependencyTransformers/AddRowsTransformer' -import {RemoveRowsTransformer} from '../../src/dependencyTransformers/RemoveRowsTransformer' -import {FunctionRegistry} from '../../src/interpreter/FunctionRegistry' -import {EmptyValue} from '../../src/interpreter/InterpreterValue' -import {SimpleRangeValue} from '../../src' -import {LazilyTransformingAstService} from '../../src/LazilyTransformingAstService' -import {ColumnIndex} from '../../src/Lookup/ColumnIndex' -import {NamedExpressions} from '../../src/NamedExpressions' -import {ColumnsSpan, RowsSpan} from '../../src/Span' -import {Statistics} from '../../src/statistics' -import {adr, detailedError, expectColumnIndexToMatchSheet} from './testUtils' -import { ErrorMessage } from '../../src/error-message' - -function buildEmptyIndex(transformingService: LazilyTransformingAstService, config: Config, statistics: Statistics): ColumnIndex { - const functionRegistry = new FunctionRegistry(config) - const namedExpression = new NamedExpressions() - const dependencyGraph = DependencyGraph.buildEmpty(transformingService, config, functionRegistry, namedExpression, statistics) - return new ColumnIndex(dependencyGraph, config, statistics) -} - -describe('ColumnIndex#add', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - - it('should add value to empty index', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('B5')) - - const columnMap = index.getColumnMap(0, 1) - - expect(columnMap.size).toBe(1) - - expect(columnMap.get(1)!.index[0]).toBe(4) - }) - - it('should keep values in sorted order', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A3')) - index.add(1, adr('A5')) - index.add(1, adr('A1')) - - const columnMap = index.getColumnMap(0, 0) - - expect(columnMap.size).toBe(1) - - expect(columnMap.get(1)!.index[0]).toBe(0) - }) - - it('should not store duplicates', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(1, adr('A5')) - index.add(1, adr('A5')) - index.add(1, adr('A1')) - index.add(1, adr('A1')) - - const columnMap = index.getColumnMap(0, 0) - - expect(columnMap.size).toBe(1) - - expect(columnMap.get(1)!.index.length).toBe(2) - }) - - it('should ignore CellErrors', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - const error = new CellError(ErrorType.DIV_BY_ZERO) - - index.add(error, adr('A1')) - - const columnMap = index.getColumnMap(0, 0) - expect(columnMap.size).toBe(0) - expect(columnMap.keys()).not.toContain(error) - }) - - it('should add values from SimpleRangeValue', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - const simpleRangeValue = SimpleRangeValue.onlyNumbers([[1, 2]]) - - index.add(simpleRangeValue, adr('A1')) - - const columnA = index.getColumnMap(0, 0) - const columnB = index.getColumnMap(0, 1) - - expect(columnA.size).toBe(1) - expect(columnB.size).toBe(1) - }) - - it('should handle strings correctly', () => { - const index = buildEmptyIndex(transformingService, new Config({ - caseSensitive: false, - accentSensitive: false - }), statistics) - index.add('a', adr('A1')) - index.add('A', adr('A2')) - index.add('ą', adr('A3')) - - // Some strings don't have a canonical form, so for them, the index is created as usual. - index.add('l', adr('A4')) - index.add('ł', adr('A5')) - index.add('t', adr('A6')) - index.add('ŧ', adr('A7')) - - const columnMap = index.getColumnMap(0, 0) - - expect(columnMap.get('a')!.index.length).toBe(3) - expect(columnMap.get('l')!.index.length).toBe(1) - expect(columnMap.get('ł')!.index.length).toBe(1) - expect(columnMap.get('t')!.index.length).toBe(1) - expect(columnMap.get('ŧ')!.index.length).toBe(1) - }) - - it('should ignore EmptyValue', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(EmptyValue, adr('A1')) - expect(index.getColumnMap(0, 0).size).toBe(0) - }) -}) - -describe('ColumnIndex change/remove', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - - it('should remove value from index', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(1, adr('A2')) - index.add(1, adr('A3')) - - index.remove(1, adr('A2')) - - - const valueIndex = index.getColumnMap(0, 0).get(1)! - expect(valueIndex.index.length).toBe(2) - expect(valueIndex.index).toContain(0) - expect(valueIndex.index).toContain(2) - }) - - it('should do nothing if passed value is undefined', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(1, adr('A2')) - index.add(1, adr('A3')) - - index.remove(undefined, adr('A2')) - - - const valueIndex = index.getColumnMap(0, 0).get(1)! - expect(valueIndex.index.length).toBe(3) - expect(valueIndex.index).toContain(0) - expect(valueIndex.index).toContain(1) - expect(valueIndex.index).toContain(2) - }) - - it('should change value in index', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - index.change(1, 2, adr('A1')) - - expect(index.getColumnMap(0, 0).keys()).not.toContain(1) - - const valueIndex = index.getColumnMap(0, 0).get(2)! - expect(valueIndex.index).toContain(0) - }) - - it('should do nothing when changing to the same value', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - const spyRemove = spyOn(index, 'remove') - const spyAdd = spyOn(index, 'add') - - index.change(1, 1, adr('A1')) - - expect(spyRemove).not.toHaveBeenCalled() - expect(spyAdd).not.toHaveBeenCalled() - }) - - it('should change range values', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - const range = SimpleRangeValue.onlyNumbers([ - [1, 2], - [3, 4], - ]) - index.add(range, adr('A1')) - deepStrictEqual(index.getColumnMap(0, 0), new Map([ - [1, {index: [0], version: 0}], - [3, {index: [1], version: 0}], - ])) - deepStrictEqual(index.getColumnMap(0, 1), new Map([ - [2, {index: [0], version: 0}], - [4, {index: [1], version: 0}], - ])) - - index.change(range, SimpleRangeValue.onlyNumbers([ - [5, 6], - [7, 8], - ]), adr('A1')) - - deepStrictEqual(index.getColumnMap(0, 0), new Map([ - [5, {index: [0], version: 0}], - [7, {index: [1], version: 0}], - ])) - deepStrictEqual(index.getColumnMap(0, 1), new Map([ - [6, {index: [0], version: 0}], - [8, {index: [1], version: 0}], - ])) - }) - - it('should ignore CellErrors', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - const error = new CellError(ErrorType.DIV_BY_ZERO) - index.change(1, error, adr('A1')) - - expect(index.getColumnMap(0, 0).keys()).not.toContain(1) - expect(index.getColumnMap(0, 0).keys()).not.toContain(error) - }) - - it('should ignore EmptyValue', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - index.change(1, EmptyValue, adr('A1')) - - expect(index.getColumnMap(0, 0).size).toBe(0) - }) -}) - -describe('ColumnIndex#addColumns', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - - it('should add column to index', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - index.addColumns(ColumnsSpan.fromNumberOfColumns(0, 0, 1)) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([]) - expect(index.getValueIndex(0, 1, 1).index).toEqual([0]) - }) - - it('should add columns in the middle', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(1, adr('B1')) - index.add(1, adr('C1')) - - index.addColumns(ColumnsSpan.fromNumberOfColumns(0, 1, 2)) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0]) - expect(index.getValueIndex(0, 3, 1).index).toEqual([0]) - expect(index.getValueIndex(0, 4, 1).index).toEqual([0]) - }) - - it('should add columns only in one sheet', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('B1')) - index.add(1, adr('B1', 1)) - - index.addColumns(ColumnsSpan.fromNumberOfColumns(0, 1, 2)) - - expect(index.getValueIndex(0, 1, 1).index).toEqual([]) - expect(index.getValueIndex(0, 3, 1).index).toEqual([0]) - expect(index.getValueIndex(1, 1, 1).index).toEqual([0]) - }) -}) - -describe('ColumnIndex#removeColumns', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - - it('should remove column', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - index.removeColumns(ColumnsSpan.fromNumberOfColumns(0, 0, 1)) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([]) - }) - - it('should work when empty index', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - - index.removeColumns(ColumnsSpan.fromNumberOfColumns(0, 0, 1)) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([]) - }) - - it('should remove multiple columns in the middle', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(2, adr('B1')) - index.add(3, adr('C1')) - index.add(4, adr('D1')) - - index.removeColumns(ColumnsSpan.fromNumberOfColumns(0, 1, 2)) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0]) - expect(index.getValueIndex(0, 1, 4).index).toEqual([0]) - expect(index.getValueIndex(0, 2, 3).index).toEqual([]) - expect(index.getValueIndex(0, 3, 4).index).toEqual([]) - }) - - it('should remove columns only in one sheet', () => { - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1', 0)) - index.add(1, adr('A1', 1)) - - index.removeColumns(ColumnsSpan.fromNumberOfColumns(0, 0, 1)) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([]) - expect(index.getValueIndex(1, 0, 1).index).toEqual([0]) - }) -}) - -describe('ColumnIndex#find', () => { - const stats = new Statistics() - const transformService = new LazilyTransformingAstService(stats) - - it('should find row number', () => { - const index = buildEmptyIndex(transformService, new Config(), stats) - - index.add(1, adr('A2')) - const row = index.find(1, SimpleRangeValue.onlyRange(new AbsoluteCellRange(adr('A1'), adr('A3')), undefined!), { ordering: 'asc', ifNoMatch: 'returnNotFound' }) - - expect(row).toBe(1) - }) - - it('should find the smallest row number for value if range not sorted', () => { - const index = buildEmptyIndex(transformService, new Config(), stats) - - index.add(1, adr('A4')) - index.add(1, adr('A10')) - const row = index.find(1, SimpleRangeValue.onlyRange(new AbsoluteCellRange(adr('A1'), adr('A20')), undefined!), { ordering: 'none', ifNoMatch: 'returnNotFound' }) - - expect(row).toBe(3) - }) - - it('should find the largest row number for value if range sorted ascending', () => { - const index = buildEmptyIndex(transformService, new Config(), stats) - - index.add(1, adr('A4')) - index.add(1, adr('A10')) - const row = index.find(1, SimpleRangeValue.onlyRange(new AbsoluteCellRange(adr('A1'), adr('A20')), undefined!), { ordering: 'asc', ifNoMatch: 'returnNotFound' }) - - expect(row).toBe(9) - }) -}) - -describe('ColumnIndex#addRows', () => { - it('should add row', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(2, adr('B3')) - - transformingService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(0, 0, 1))) - transformingService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(1, 0, 1))) - - index.ensureRecentData(0, 0, 1) - expect(index.getValueIndex(0, 0, 1).index).toEqual([1]) - index.ensureRecentData(0, 1, 2) - expect(index.getValueIndex(0, 1, 2).index).toEqual([3]) - }) - - it('should not shift row', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - transformingService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(0, 1, 1))) - index.ensureRecentData(0, 0, 1) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0]) - }) - - it('should add rows in the middle', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(1, adr('A2')) - index.add(1, adr('A3')) - index.add(1, adr('A4')) - - transformingService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(0, 1, 2))) - index.ensureRecentData(0, 0, 1) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0, 3, 4, 5]) - }) - - it('should add rows for all columns', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A2')) - index.add(1, adr('B2')) - index.add(2, adr('C2')) - - transformingService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(0, 1, 2))) - index.ensureRecentData(0, 0, 1) - index.ensureRecentData(0, 1, 1) - index.ensureRecentData(0, 2, 2) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([3]) - expect(index.getValueIndex(0, 1, 1).index).toEqual([3]) - expect(index.getValueIndex(0, 2, 2).index).toEqual([3]) - }) - - it('should add rows for different values', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(2, adr('A2')) - index.add(3, adr('A3')) - index.add(4, adr('B1')) - index.add(4, adr('B5')) - - transformingService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(0, 1, 2))) - index.ensureRecentData(0, 0, 1) - index.ensureRecentData(0, 0, 2) - index.ensureRecentData(0, 0, 3) - index.ensureRecentData(0, 1, 4) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0]) - expect(index.getValueIndex(0, 0, 2).index).toEqual([3]) - expect(index.getValueIndex(0, 0, 3).index).toEqual([4]) - expect(index.getValueIndex(0, 1, 4).index).toEqual([0, 6]) - }) -}) - -describe('ColumnIndex#removeRows', () => { - it('should remove rows', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - - transformingService.addTransformation(new RemoveRowsTransformer(RowsSpan.fromNumberOfRows(0, 0, 1))) - index.ensureRecentData(0, 0, 1) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([]) - }) - - it('should remove rows in the middle', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(1, adr('A2')) - index.add(1, adr('A3')) - index.add(1, adr('A4')) - - transformingService.addTransformation(new RemoveRowsTransformer(RowsSpan.fromNumberOfRows(0, 1, 2))) - index.ensureRecentData(0, 0, 1) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0, 1]) - }) - - it('should remove rows in every column', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A2')) - index.add(1, adr('B2')) - index.add(1, adr('C2')) - - transformingService.addTransformation(new RemoveRowsTransformer(RowsSpan.fromNumberOfRows(0, 0, 1))) - index.ensureRecentData(0, 0, 1) - index.ensureRecentData(0, 1, 1) - index.ensureRecentData(0, 2, 1) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0]) - expect(index.getValueIndex(0, 1, 1).index).toEqual([0]) - expect(index.getValueIndex(0, 2, 1).index).toEqual([0]) - }) - - it('should remove rows for different values', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A2')) - index.add(2, adr('A3')) - index.add(3, adr('A4')) - index.add(4, adr('B3')) - - transformingService.addTransformation(new RemoveRowsTransformer(RowsSpan.fromNumberOfRows(0, 0, 2))) - index.ensureRecentData(0, 0, 1) - index.ensureRecentData(0, 0, 2) - index.ensureRecentData(0, 0, 3) - index.ensureRecentData(0, 1, 4) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([]) - expect(index.getValueIndex(0, 0, 2).index).toEqual([0]) - expect(index.getValueIndex(0, 0, 3).index).toEqual([1]) - expect(index.getValueIndex(0, 1, 4).index).toEqual([0]) - }) - - it('should remove rows only in one sheet', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A2')) - index.add(1, adr('A2', 1)) - - transformingService.addTransformation(new RemoveRowsTransformer(RowsSpan.fromNumberOfRows(0, 0, 1))) - index.ensureRecentData(0, 0, 1) - index.ensureRecentData(1, 0, 1) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0]) - expect(index.getValueIndex(1, 0, 1).index).toEqual([1]) - }) - - it('should remove proper rows', () => { - const statistics = new Statistics() - const transformingService = new LazilyTransformingAstService(statistics) - const index = buildEmptyIndex(transformingService, new Config(), statistics) - index.add(1, adr('A1')) - index.add(1, adr('A3')) - index.add(1, adr('A4')) - index.add(1, adr('A6')) - - transformingService.addTransformation(new RemoveRowsTransformer(RowsSpan.fromNumberOfRows(0, 1, 4))) - index.ensureRecentData(0, 0, 1) - - expect(index.getValueIndex(0, 0, 1).index).toEqual([0, 1]) - }) -}) - -describe('ColumnIndex - lazy crud operations', () => { - it('should add rows only in specific column after find', () => { - const stats = new Statistics() - const transformService = new LazilyTransformingAstService(stats) - const index = buildEmptyIndex(transformService, new Config(), stats) - index.add(1, adr('A1')) - index.add(1, adr('B1')) - - transformService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(0, 0, 1))) - - const rowA = index.find(1, SimpleRangeValue.onlyRange(new AbsoluteCellRange(adr('A1'), adr('A2')), undefined!), { ordering: 'asc', ifNoMatch: 'returnNotFound' }) - expect(rowA).toEqual(1) - expect(index.getValueIndex(0, 0, 1).index).toEqual([1]) - expect(index.getValueIndex(0, 1, 1).index).toEqual([0]) - - const rowB = index.find(1, SimpleRangeValue.onlyRange(new AbsoluteCellRange(adr('B1'), adr('B2')), undefined!), { ordering: 'asc', ifNoMatch: 'returnNotFound' }) - expect(rowB).toEqual(1) - expect(index.getValueIndex(0, 0, 1).index).toEqual([1]) - expect(index.getValueIndex(0, 1, 1).index).toEqual([1]) - }) - - it('should add rows only for specific value after find', () => { - const stats = new Statistics() - const transformService = new LazilyTransformingAstService(stats) - const index = buildEmptyIndex(transformService, new Config(), stats) - index.add(1, adr('A1')) - index.add(2, adr('A2')) - - transformService.addTransformation(new AddRowsTransformer(RowsSpan.fromNumberOfRows(0, 0, 1))) - - const row1 = index.find(1, SimpleRangeValue.onlyRange(new AbsoluteCellRange(adr('A1'), adr('A3')), undefined!), { ordering: 'asc', ifNoMatch: 'returnNotFound' }) - expect(row1).toEqual(1) - expect(index.getValueIndex(0, 0, 1).index).toEqual([1]) - expect(index.getValueIndex(0, 0, 2).index).toEqual([1]) - - const row2 = index.find(2, SimpleRangeValue.onlyRange(new AbsoluteCellRange(adr('A1'), adr('A3')), undefined!), { ordering: 'asc', ifNoMatch: 'returnNotFound' }) - expect(row2).toEqual(2) - expect(index.getValueIndex(0, 0, 1).index).toEqual([1]) - expect(index.getValueIndex(0, 0, 2).index).toEqual([2]) - }) -}) - -describe('Arrays', () => { - it('should update column index with array values', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=-A1:B1'], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - expectColumnIndexToMatchSheet([ - [1, 2, -1, -2] - ], engine) - }) - - it('should remove values from index when REF', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=-A1:B1'], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.setCellContents(adr('D1'), [['foo']]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - - expectColumnIndexToMatchSheet([ - [1, 2, null, 'foo'] - ], engine) - }) - - it('should remove values from index when replacing array with scalar', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=-A1:B1'], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.setCellContents(adr('C1'), [['foo']]) - - expectColumnIndexToMatchSheet([ - [1, 2, 'foo'] - ], engine) - }) - - it('should remove values when replacing array with smaller one', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=-A1:B1'], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.setCellContents(adr('C1'), [['=2*A1:A1']]) - - expectColumnIndexToMatchSheet([ - [1, 2, 2] - ], engine) - }) - - it('should remove values when replacing array with parsing error', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=-A1:B1'], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.setCellContents(adr('C1'), [['=SUM(']]) - - expectColumnIndexToMatchSheet([ - [1, 2] - ], engine) - }) - - it('should update index when replacing array with another one', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=-A1:B1'], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.setCellContents(adr('C1'), [['=2*A1:B1']]) - - expectColumnIndexToMatchSheet([ - [1, 2, 2, 4] - ], engine) - }) - - it('should move array values when adding rows above array', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B3:B4'], - [null, 'foo'], - [null, 1], - [null, 2], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.addRows(0, [0, 1]) - - expectColumnIndexToMatchSheet([ - [null], - [-1], - [-2, 'foo'], - [null, 1], - [null, 2], - ], engine) - }) - - it('should not move array values when adding rows', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B3:B4'], - [null, 'foo'], - [-2, 1], - [-1, 2], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.addRows(0, [1, 1]) - - expectColumnIndexToMatchSheet([ - [-1], - [-2], - [null, 'foo'], - [-2, 1], - [-1, 2], - ], engine) - }) - - it('should move array values when removing rows above array', () => { - const engine = HyperFormula.buildFromArray([ - [], - ['=-B3:B4'], - [null, 1], - [null, 2], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeRows(0, [0, 1]) - - expectColumnIndexToMatchSheet([ - [-1], - [-2, 1], - [null, 2] - ], engine) - }) - - it('should not move array values when removing rows', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B4:B5'], - [null], - [null, 'foo'], - [-2, 1], - [-1, 2], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeRows(0, [1, 1]) - - expectColumnIndexToMatchSheet([ - [-1], - [-2, 'foo'], - [-2, 1], - [-1, 2], - ], engine) - }) - - it('should remove array values from index when removing row with left corner', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B2:B3'], - [null, 1], - [null, 2], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeRows(0, [0, 1]) - - expectColumnIndexToMatchSheet([ - [null, 1], - [null, 2] - ], engine) - }) - - it('should remove array values from index when REF after removing rows', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B2:B3'], - [null, 1], - [3, 2], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeRows(0, [1, 1]) - - expectColumnIndexToMatchSheet([ - [], - [3, 2] - ], engine) - }) - - it('should move array values when adding columns before array', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C2:D2'], - [null, 'foo', 1, 2] - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.addColumns(0, [0, 1]) - - expectColumnIndexToMatchSheet([ - [null, -1, -2], - [null, null, 'foo', 1, 2] - ], engine) - }) - - it('should not move array values when adding columns', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C2:E2', null, null, -3, -2, -1], - [null, 'foo', 1, 2, 3] - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.addColumns(0, [1, 1]) - - expectColumnIndexToMatchSheet([ - [-1, -2, -3, null, -3, -2, -1], - [null, null, 'foo', 1, 2, 3] - ], engine) - }) - - it('should move array values when removing columns before array', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=-C2:D2'], - [null, null, 1, 2] - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeColumns(0, [0, 1]) - - expectColumnIndexToMatchSheet([ - [-1, -2], - [null, 1, 2] - ], engine) - }) - - it('should not move array values when removing columns', () => { - const engine = HyperFormula.buildFromArray([ - ['=-D2:E2', null, null, -2, -1], - [-2, 'foo', null, 1, 2] - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeColumns(0, [1, 1]) - - expectColumnIndexToMatchSheet([ - [-1, -2, -2, -1], - [-2, null, 1, 2] - ], engine) - }) - - it('should remove array values from index when removing column with left corner', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B2:C2'], - [null, 1, 2], - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeColumns(0, [0, 1]) - - expectColumnIndexToMatchSheet([ - [], - [1, 2], - ], engine) - }) - - it('should remove array values from index when REF after removing columns', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B2:C2', null, 1], - [2, null, 3] - ], {useArrayArithmetic: true, useColumnIndex: true}) - - engine.removeColumns(0, [1, 1]) - - expectColumnIndexToMatchSheet([ - [null, 1], - [2, 3] - ], engine) - }) -}) diff --git a/test/unit/column-range.spec.ts b/test/unit/column-range.spec.ts deleted file mode 100644 index a538063c56..0000000000 --- a/test/unit/column-range.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -import {HyperFormula} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {adr, colEnd, colStart, extractColumnRange} from './testUtils' -import {RangeVertex} from '../../src/DependencyGraph' - -describe('Column ranges', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A:B)'] - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(3) - }) - - it('should create correct edges for infinite range when building graph', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(C:D)', '=SUM(C5:D6)'], - ]) - - const cd = engine.rangeMapping.getRangeVertex(colStart('C'), colEnd('D')) as RangeVertex - - const c5 = engine.dependencyGraph.fetchCell(adr('C5')) - const c6 = engine.dependencyGraph.fetchCell(adr('C6')) - const d5 = engine.dependencyGraph.fetchCell(adr('D5')) - const d6 = engine.dependencyGraph.fetchCell(adr('D6')) - - expect(engine.graph.existsEdge(c5, cd)).toBe(true) - expect(engine.graph.existsEdge(c6, cd)).toBe(true) - expect(engine.graph.existsEdge(d5, cd)).toBe(true) - expect(engine.graph.existsEdge(d6, cd)).toBe(true) - }) - - it('should create correct edges for infinite range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(C:E)'], - ['=SUM(D:G)'], - ]) - - engine.setCellContents(adr('B1'), '=SUM(D42:H42)') - - const ce = engine.rangeMapping.getRangeVertex(colStart('C'), colEnd('E')) as RangeVertex - const dg = engine.rangeMapping.getRangeVertex(colStart('D'), colEnd('G')) as RangeVertex - - const d42 = engine.dependencyGraph.fetchCell(adr('D42')) - const e42 = engine.dependencyGraph.fetchCell(adr('E42')) - const f42 = engine.dependencyGraph.fetchCell(adr('F42')) - const g42 = engine.dependencyGraph.fetchCell(adr('G42')) - const h42 = engine.dependencyGraph.fetchCell(adr('H42')) - - expect(engine.graph.existsEdge(d42, ce)).toBe(true) - expect(engine.graph.existsEdge(e42, ce)).toBe(true) - expect(engine.graph.existsEdge(f42, ce)).toBe(false) - - expect(engine.graph.existsEdge(d42, dg)).toBe(true) - expect(engine.graph.existsEdge(e42, dg)).toBe(true) - expect(engine.graph.existsEdge(f42, dg)).toBe(true) - expect(engine.graph.existsEdge(g42, dg)).toBe(true) - expect(engine.graph.existsEdge(h42, dg)).toBe(false) - }) - - it('should clear column range set in graph when removing column', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B:B)'] - ]) - - engine.removeColumns(0, [1, 1]) - - expect(engine.graph.getInfiniteRanges().length).toBe(0) - }) - - it('should not move infinite range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '', '', '=SUM(A:B)'] - ]) - expect(engine.getCellValue(adr('E1'))).toEqual(3) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1), adr('C1')) - - expect(engine.getCellValue(adr('E1'))).toEqual(0) - const range = extractColumnRange(engine, adr('E1')) - expect(range.start).toEqual(colStart('A')) - expect(range.end).toEqual(colEnd('B')) - }) - - it('should correctly handle infinite column ranges when setting cell values (line 890)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(C:D)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - - engine.setCellContents(adr('C5'), 10) - engine.setCellContents(adr('D5'), 20) - - expect(engine.getCellValue(adr('A1'))).toBe(30) - }) -}) diff --git a/test/unit/computation-suspension.spec.ts b/test/unit/computation-suspension.spec.ts deleted file mode 100644 index 836e791370..0000000000 --- a/test/unit/computation-suspension.spec.ts +++ /dev/null @@ -1,227 +0,0 @@ -import {EvaluationSuspendedError, ExportedCellChange, HyperFormula} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {CellType} from '../../src/Cell' -import {adr} from './testUtils' - -describe('Evaluation suspension', () => { - it('by default, evaluation is automatic', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1'], - ]) - - engine.setCellContents(adr('C1'), [['=B1']]) - - expect(engine.getCellValue(adr('C1'))).toBe(2) - }) - - it('when evaluation is stopped, getting cell values is forbidden', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '42'], - ]) - - engine.suspendEvaluation() - - expect(() => { - engine.getCellValue(adr('C1')) - }).toThrow(new EvaluationSuspendedError()) - expect(() => { - engine.getSheetValues(0) - }).toThrow(new EvaluationSuspendedError()) - expect(() => { - engine.getAllSheetsValues() - }).toThrow(new EvaluationSuspendedError()) - expect(() => { - engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2)) - }).toThrow(new EvaluationSuspendedError()) - expect(() => { - engine.getNamedExpressionValue('FOO') - }).toThrow(new EvaluationSuspendedError()) - }) - - it('when evaluation is stopped, getting serialized cell values is forbidden', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '42'], - ]) - - engine.suspendEvaluation() - - expect(() => { - engine.getCellSerialized(adr('C1')) - }).toThrow(new EvaluationSuspendedError()) - expect(() => { - engine.getSheetSerialized(0) - }).toThrow(new EvaluationSuspendedError()) - expect(() => { - engine.getAllSheetsSerialized() - }).toThrow(new EvaluationSuspendedError()) - expect(() => { - engine.getRangeSerialized(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2)) - }).toThrow(new EvaluationSuspendedError()) - }) - - it('when evaluation is stopped, getting cell value types is forbidden', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '42'], - ]) - - engine.suspendEvaluation() - - expect(() => { - engine.getCellValueType(adr('C1')) - }).toThrow(new EvaluationSuspendedError()) - }) - - it('when evaluation is stopped, getting cell types is possible', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '42'], - ]) - - engine.suspendEvaluation() - engine.setCellContents(adr('C1'), [['=A1+78']]) - - expect(engine.getCellType(adr('C1'))).toEqual(CellType.FORMULA) - expect(engine.doesCellHaveSimpleValue(adr('C1'))).toBe(false) - expect(engine.doesCellHaveFormula(adr('C1'))).toBe(true) - expect(engine.isCellEmpty(adr('C1'))).toBe(false) - expect(engine.isCellPartOfArray(adr('C1'))).toBe(false) - }) - - it('when evaluation is stopped, getting cell formulas is possible', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1+42'], - ]) - engine.suspendEvaluation() - engine.setCellContents(adr('C1'), [['=A1+78']]) - - expect(engine.getCellFormula(adr('C1'))).toEqual('=A1+78') - expect(engine.getSheetFormulas(0)).toEqual([[undefined, undefined, '=A1+78']]) - expect(engine.getAllSheetsFormulas()).toEqual({Sheet1: [[undefined, undefined, '=A1+78']]}) - expect(engine.getRangeFormulas(AbsoluteCellRange.spanFrom(adr('A1'), 3, 1))).toEqual([[undefined, undefined, '=A1+78']]) - }) - - it('formulas are rebuild even if evaluation is suspended', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A2+42'], - ['42'] - ]) - engine.suspendEvaluation() - - engine.addRows(0, [1, 1]) - - expect(engine.getCellFormula(adr('C1'))).toEqual('=A3+42') - }) - - it('resuming evaluation', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1'], - ]) - engine.suspendEvaluation() - engine.setCellContents(adr('C1'), [['=B1']]) - - const changes = engine.resumeEvaluation() - - expect(engine.getCellValue(adr('C1'))).toBe(2) - expect(changes).toContainEqual(new ExportedCellChange(adr('C1'), 2)) - }) - - it('#isEvaluationSuspended when evaluation is suspended', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1'], - ]) - engine.suspendEvaluation() - - expect(engine.isEvaluationSuspended()).toBe(true) - }) - - it('#isEvaluationSuspended when evaluation is resumed', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1'], - ]) - - expect(engine.isEvaluationSuspended()).toBe(false) - }) - - describe('clipboard operations depend on values, so they are forbidden', () => { - it('copy', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1'], - ]) - engine.suspendEvaluation() - - expect(() => { - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - }).toThrow(new EvaluationSuspendedError()) - }) - - it('cut', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1'], - ]) - engine.suspendEvaluation() - - expect(() => { - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - }).toThrow(new EvaluationSuspendedError()) - }) - - it('paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1'], - ]) - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.suspendEvaluation() - - expect(() => { - engine.paste(adr('A3')) - }).toThrow(new EvaluationSuspendedError()) - }) - }) - - it('undo-redo works when computation suspended', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A2+42'], - ['42'] - ]) - engine.suspendEvaluation() - engine.addRows(0, [1, 1]) - - engine.undo() - - expect(engine.getCellFormula(adr('C1'))).toEqual('=A2+42') - }) - - it('#1291 - neighboring cell changes of an array formula should be emitted', () => { - const engine = HyperFormula.buildFromArray([[null, null, null]], { useArrayArithmetic: true }) - engine.suspendEvaluation() - - engine.setCellContents(adr('A1'), '={1;2;3}') - engine.setCellContents(adr('B1'), '4') - engine.setCellContents(adr('C1'), '5') - - const changes = engine.resumeEvaluation() - expect(changes.length).toEqual(5) - expect(changes).toContainEqual(new ExportedCellChange(adr('A1'), 1)) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), 2)) - expect(changes).toContainEqual(new ExportedCellChange(adr('A3'), 3)) - expect(changes).toContainEqual(new ExportedCellChange(adr('B1'), 4)) - expect(changes).toContainEqual(new ExportedCellChange(adr('C1'), 5)) - }) - - it('allows to update cell content of a not computed formula cell (#1194)', () => { - const hf = HyperFormula.buildFromArray([], { - licenseKey: 'gpl-v3' - }) - - hf.suspendEvaluation() - hf.setCellContents(adr('A1'), '=42') - hf.setCellContents(adr('A1'), 42) - hf.setCellContents(adr('A1'), '=42') - hf.setCellContents(adr('A1'), null) - hf.setCellContents(adr('A1'), '=42') - hf.setCellContents(adr('A1'), '==') - hf.setCellContents(adr('A1'), '=42') - hf.setCellContents(adr('A1'), '=42') - hf.resumeEvaluation() - expect(hf.getCellValue(adr('A1'))).toBe(42) - }) -}) diff --git a/test/unit/config.spec.ts b/test/unit/config.spec.ts deleted file mode 100644 index 3c79abed00..0000000000 --- a/test/unit/config.spec.ts +++ /dev/null @@ -1,423 +0,0 @@ -import {ErrorType, HyperFormula, MissingTranslationError} from '../../src' -import {Config} from '../../src/Config' -import {enGB, plPL} from '../../src/i18n/languages' -import {EmptyValue, NumberType} from '../../src/interpreter/InterpreterValue' -import {adr, unregisterAllLanguages} from './testUtils' -import {CellValueNoNumber} from '../../src/Cell' -import {UIElement} from '../../src/i18n' - -describe('Config', () => { - beforeEach(() => { - unregisterAllLanguages() - HyperFormula.registerLanguage(plPL.langCode, plPL) - HyperFormula.registerLanguage(enGB.langCode, enGB) - }) - - it('works', () => { - const config = new Config({language: 'plPL'}) - - expect(config.language).toBe('plPL') - }) - - it('has some defaults', () => { - const config = new Config() - - expect(config.language).toBe(Config.defaultConfig.language) - }) - - it('can translate functions', () => { - const config = new Config({language: 'plPL'}) - - expect(config.translationPackage.getFunctionTranslation('SUM')).toEqual('SUMA') - }) - - it('validation: boolean params', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({ignorePunctuation: 1})).toThrowError('Expected value of type: boolean for config parameter: ignorePunctuation') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({accentSensitive: 'abcd'})).toThrowError('Expected value of type: boolean for config parameter: accentSensitive') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({caseSensitive: 'abcd'})).toThrowError('Expected value of type: boolean for config parameter: caseSensitive') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({smartRounding: []})).toThrowError('Expected value of type: boolean for config parameter: smartRounding') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({useColumnIndex: Symbol()})).toThrowError('Expected value of type: boolean for config parameter: useColumnIndex') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({leapYear1900: () => 1})).toThrowError('Expected value of type: boolean for config parameter: leapYear1900') - }) - - it('validation: number params', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({nullYear: true})).toThrowError('Expected value of type: number for config parameter: nullYear') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({precisionRounding: /abcd/})).toThrowError('Expected value of type: number for config parameter: precisionRounding') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({precisionEpsilon: {}})).toThrowError('Expected value of type: number for config parameter: precisionEpsilon') - }) - - it('validation: string params', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({functionArgSeparator: 123})).toThrowError('Expected value of type: string for config parameter: functionArgSeparator') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({localeLang: EmptyValue})).toThrowError('Expected value of type: string for config parameter: localeLang') - }) - - it('validation: function params', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({parseDateTime: true})).toThrowError('Expected value of type: function for config parameter: parseDateTime') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({stringifyDateTime: 1})).toThrowError('Expected value of type: function for config parameter: stringifyDateTime') - }) - - it('validation: other params', () => { - expect(() => new Config({ - // eslint-disable-next-line - // @ts-ignore - nullDate: {year: 123, month: 123, day: true} - })).toThrowError('Expected value of type: IDate for config parameter: nullDate') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({dateFormats: {}})).toThrowError('Expected value of type: array for config parameter: dateFormats') - // eslint-disable-next-line - // @ts-ignore - expect(() => new Config({caseFirst: 'abcd'})).toThrowError('Expected one of \'upper\' \'lower\' \'false\' for config parameter: caseFirst') - }) - - it('should return the specified context', () => { - const context ={a: 1, b: 2} - const config = new Config({context}) - expect(config.context).toBe(context) - }) - - it('should throw error when Function Translation cannot be found', () => { - const config = new Config() - const functionName = '0123456ABCDEFGH' - expect(() => { - config.translationPackage.getFunctionTranslation(functionName) - }).toThrow(new MissingTranslationError(`functions.${functionName}`)) - }) - - it('should throw error when Error Translation cannot be found', () => { - const config = new Config() - const errorType = '0123456ABCDEFGH' - expect(() => { - config.translationPackage.getErrorTranslation(errorType as ErrorType) - }).toThrow(new MissingTranslationError(`errors.${errorType}`)) - }) - - it('should throw error when UI Translation cannot be found', () => { - const config = new Config() - const uiElement = '0123456ABCDEFGH' - expect(() => { - config.translationPackage.getUITranslation(uiElement as UIElement) - }).toThrow(new MissingTranslationError(`ui.${uiElement}`)) - }) - - it('should throw error when there is a conflict between separators', () => { - expect(() => { - new Config({decimalSeparator: ',', functionArgSeparator: ',', thousandSeparator: ' '}) - }).toThrowError('Config initialization failed. Parameters in conflict: [decimalSeparator,functionArgSeparator]') - expect(() => { - new Config({decimalSeparator: ',', functionArgSeparator: ';', thousandSeparator: ','}) - }).toThrowError('Config initialization failed. Parameters in conflict: [decimalSeparator,thousandSeparator]') - expect(() => { - new Config({decimalSeparator: '.', functionArgSeparator: ',', thousandSeparator: ','}) - }).toThrowError('Config initialization failed. Parameters in conflict: [functionArgSeparator,thousandSeparator]') - expect(() => { - new Config({decimalSeparator: ',', functionArgSeparator: ',', thousandSeparator: ','}) - }).toThrowError('Config initialization failed. Parameters in conflict: [decimalSeparator,functionArgSeparator,thousandSeparator]') - expect(() => { - new Config({arrayColumnSeparator: ';', arrayRowSeparator: ';'}) - }).toThrowError('Config initialization failed. Parameters in conflict: [arrayColumnSeparator,arrayRowSeparator]') - }) - - it('should throw error when currency symbol is empty', () => { - expect(() => { - new Config({currencySymbol: ['']}) - }).toThrowError('Config parameter currencySymbol cannot be empty.') - }) - - it('should throw error when currency symbol is not a string', () => { - expect(() => { - new Config({currencySymbol: [ 42 as unknown as string ]}) - }).toThrowError('Expected value of type: string[] for config parameter: currencySymbol') - }) - - it('should throw error when currency symbol is not an array', () => { - expect(() => { - // eslint-disable-next-line - // @ts-ignore - new Config({currencySymbol: '$'}) - }).toThrowError('Expected value of type: array for config parameter: currencySymbol') - }) - - it('should throw error when decimal separator is not correct', () => { - expect(() => { - // eslint-disable-next-line - // @ts-ignore - new Config({decimalSeparator: ';'}) - }).toThrowError('Expected one of \'.\' \',\' for config parameter: decimalSeparator') - }) - - it('should throw error when thousand separator is not correct', () => { - expect(() => { - // eslint-disable-next-line - // @ts-ignore - new Config({thousandSeparator: ';'}) - }).toThrowError('Expected one of \'\' \',\' \' \' \'.\' for config parameter: thousandSeparator') - }) - - it('should throw error when matrix row separator is not correct', () => { - expect(() => { - // eslint-disable-next-line - // @ts-ignore - new Config({arrayRowSeparator: ','}) - }).toThrowError('Expected one of \';\' \'|\' for config parameter: arrayRowSeparator') - }) - - it('should throw error when matrix columns separator is not correct', () => { - expect(() => { - // eslint-disable-next-line - // @ts-ignore - new Config({arrayColumnSeparator: '|'}) - }).toThrowError('Expected one of \',\' \';\' for config parameter: arrayColumnSeparator') - }) - - it('#undoLimit validation', () => { - expect(() => new Config({undoLimit: 0})).not.toThrowError() - expect(() => new Config({undoLimit: 42})).not.toThrowError() - expect(() => new Config({undoLimit: Infinity})).not.toThrowError() - expect(() => new Config({undoLimit: -1})).toThrowError('Config parameter undoLimit should be at least 0') - }) - - it('#precisionEpsilon', () => { - expect(() => new Config({precisionEpsilon: 0})).not.toThrowError() - expect(() => new Config({precisionEpsilon: 42})).not.toThrowError() - expect(() => new Config({precisionEpsilon: Infinity})).not.toThrowError() - expect(() => new Config({precisionEpsilon: -1})).toThrowError('Config parameter precisionEpsilon should be at least 0') - }) - - it('#precisionRounding', () => { - expect(() => new Config({precisionRounding: 0})).not.toThrowError() - expect(() => new Config({precisionRounding: 42})).not.toThrowError() - expect(() => new Config({precisionRounding: Infinity})).not.toThrowError() - expect(() => new Config({precisionRounding: -1})).toThrowError('Config parameter precisionRounding should be at least 0') - }) - - it('#maxRows', () => { - expect(() => new Config({maxRows: 1})).not.toThrowError() - expect(() => new Config({maxRows: 42})).not.toThrowError() - expect(() => new Config({maxRows: Infinity})).not.toThrowError() - expect(() => new Config({maxRows: 0})).toThrowError('Config parameter maxRows should be at least 1') - }) - - it('#maxColumns', () => { - expect(() => new Config({maxColumns: 1})).not.toThrowError() - expect(() => new Config({maxColumns: 42})).not.toThrowError() - expect(() => new Config({maxColumns: Infinity})).not.toThrowError() - expect(() => new Config({maxColumns: 0})).toThrowError('Config parameter maxColumns should be at least 1') - }) - - it('#nullYear', () => { - expect(() => new Config({nullYear: -1})).toThrowError('Config parameter nullYear should be at least 0') - expect(() => new Config({nullYear: 0})).not.toThrowError() - expect(() => new Config({nullYear: 42})).not.toThrowError() - expect(() => new Config({nullYear: 100})).not.toThrowError() - expect(() => new Config({nullYear: 101})).toThrowError('Config parameter nullYear should be at most 100') - }) - - describe('#dateFormats', () => { - it('should use the data formats provided in config param', () => { - const dateFormats = ['DD/MM/YYYY'] - const engine = HyperFormula.buildFromArray([ - ['1'], - ['01/03/2022'], - ['2022/01/01'], - ], { dateFormats }) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(NumberType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A2'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('A3'))).toEqual(CellValueNoNumber.STRING) - }) - - it('should parse the dates with different separators', () => { - const dateFormats = ['DD/MM/YYYY'] - const engine = HyperFormula.buildFromArray([[ - '01/03/2022', - '01-03-2022', - '01 03 2022', - '01.03.2022', - '01/03-2022', - '01 03.2022', - '01 03/2022', - '01.03-2022', - ]], { dateFormats }) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('A1'))).toEqual('DD/MM/YYYY') - expect(engine.getCellValueDetailedType(adr('B1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('B1'))).toEqual('DD/MM/YYYY') - expect(engine.getCellValueDetailedType(adr('C1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('C1'))).toEqual('DD/MM/YYYY') - expect(engine.getCellValueDetailedType(adr('D1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('D1'))).toEqual('DD/MM/YYYY') - expect(engine.getCellValueDetailedType(adr('E1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('E1'))).toEqual('DD/MM/YYYY') - expect(engine.getCellValueDetailedType(adr('F1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('F1'))).toEqual('DD/MM/YYYY') - expect(engine.getCellValueDetailedType(adr('G1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('G1'))).toEqual('DD/MM/YYYY') - expect(engine.getCellValueDetailedType(adr('H1'))).toEqual(NumberType.NUMBER_DATE) - expect(engine.getCellValueFormat(adr('H1'))).toEqual('DD/MM/YYYY') - }) - }) - - describe('#timeFormats', () => { - it('should work with the "hh:mm" format', () => { - const timeFormats = ['hh:mm'] - const engine = HyperFormula.buildFromArray([ - ['13.33'], - ['13:33'], - ['01:33'], - ['1:33'], - ['13:33:33'], - ], { timeFormats }) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(NumberType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A2'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A3'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A4'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A5'))).toEqual(CellValueNoNumber.STRING) - }) - - it('should accept "AM/PM" designator', () => { - const timeFormats = ['hh:mm'] - const engine = HyperFormula.buildFromArray([ - ['1:33 AM'], - ['1:33 PM'], - ['01:33 am'], - ['1:33 pm'], - ['1:33AM'], - ['1:33PM'], - ['1:33 AM'], - ['1:33 PM'], - ['13:33 AM'], - ], { timeFormats }) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A2'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A3'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A4'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A5'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A6'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A7'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A8'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A9'))).toEqual(CellValueNoNumber.STRING) - }) - - it('should work with the "hh:mm:ss" format', () => { - const timeFormats = ['hh:mm:ss'] - const engine = HyperFormula.buildFromArray([ - ['13:33'], - ['1:33:33'], - ['1:33:33 AM'], - ['1:33:33 PM'], - ['1:33:33 am'], - ['1:33:33 pm'], - ['1:33:33 a'], - ['1:33:33 p'], - ['1:33:33 A'], - ['1:33:33 P'], - ['13:33:33'], - ['01:33:33'], - ['1:33:33.3'], - ['1:33:33.33'], - ['1:33:33.333'], - ['1:33:33.3333'], - ['1:33:33.333333333333333333333333333333333333333333333333333333'], - ], { timeFormats }) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueNoNumber.STRING) - expect(engine.getCellValueDetailedType(adr('A2'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A3'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A4'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A5'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A6'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A7'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A8'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A9'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A10'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A11'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A12'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A13'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A14'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A15'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A16'))).toEqual(NumberType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('A17'))).toEqual(NumberType.NUMBER_TIME) - }) - - it('the parsing result should be the same regardless of decimal places specified in format string', () => { - const dateAsString = '13:33:33.33333' - const dateAsNumber = 0.564969131944444 - - let engine = HyperFormula.buildFromArray([[dateAsString]], { timeFormats: ['hh:mm:ss'] }) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(dateAsNumber, 11) - - engine = HyperFormula.buildFromArray([[dateAsString]], { timeFormats: ['hh:mm:ss.s'] }) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(dateAsNumber, 11) - - engine = HyperFormula.buildFromArray([[dateAsString]], { timeFormats: ['hh:mm:ss.ss'] }) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(dateAsNumber, 11) - - engine = HyperFormula.buildFromArray([[dateAsString]], { timeFormats: ['hh:mm:ss.sss'] }) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(dateAsNumber, 11) - - engine = HyperFormula.buildFromArray([[dateAsString]], { timeFormats: ['hh:mm:ss.ssss'] }) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(dateAsNumber, 11) - - engine = HyperFormula.buildFromArray([[dateAsString]], { timeFormats: ['hh:mm:ss.sssss'] }) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(dateAsNumber, 11) - }) - }) -}) - -describe('getConfig', () => { - it('should not be an instance of Config', () => { - const engine = HyperFormula.buildEmpty() - expect(engine.getConfig()).not.toBeInstanceOf(Config) - }) - - it('should copy returned values', () => { - const arr = ['mm'] - const engine = HyperFormula.buildEmpty({dateFormats: arr}) - const arr2 = engine.getConfig().dateFormats - expect(arr).toEqual(arr2) - expect(arr).not.toBe(arr2) - }) -}) - -describe('getDefaultConfig', () => { - it('should not be an instance of Config', () => { - expect(HyperFormula.defaultConfig).not.toBeInstanceOf(Config) - }) - - it('should copy returned values', () => { - const defaultConfig = HyperFormula.defaultConfig - defaultConfig.dateFormats.push('mm') - const defaultDateFormats = HyperFormula.defaultConfig.dateFormats - expect(defaultDateFormats).toEqual(['DD/MM/YYYY', 'DD/MM/YY']) - }) -}) diff --git a/test/unit/content-changes.spec.ts b/test/unit/content-changes.spec.ts deleted file mode 100644 index c6ca4e4774..0000000000 --- a/test/unit/content-changes.spec.ts +++ /dev/null @@ -1,113 +0,0 @@ -import {CellValueChange, ChangeExporter, ContentChanges} from '../../src/ContentChanges' -import {SimpleRangeValue} from '../../src/SimpleRangeValue' -import {adr} from './testUtils' - -class SimpleChangeExporter implements ChangeExporter { - exportChange(change: CellValueChange): CellValueChange { - return {address: change.address, value: change.value} - } -} - -class SpreadRangeExporter implements ChangeExporter { - exportChange(change: CellValueChange): CellValueChange | CellValueChange[] { - const value = change.value - const address = change.address - if (value instanceof SimpleRangeValue) { - return Array.from(value.entriesFromTopLeftCorner(address)).map(([v, a]) => { - return {address: a, value: v} - }) - } else { - return {address: address, value: value} - } - } -} - -describe('ContentChanges', () => { - const simpleChangeExporter = new SimpleChangeExporter() - const spreadRangeExporter = new SpreadRangeExporter() - - it('should be empty', () => { - const contentChanges = ContentChanges.empty() - - expect(contentChanges.isEmpty()).toEqual(true) - }) - - it('should replace simple value change', () => { - const contentChanges = ContentChanges.empty() - - contentChanges.addChange(1, adr('A1')) - contentChanges.addChange(2, adr('A1')) - - const exportedChanges = contentChanges.exportChanges(simpleChangeExporter) - expect(exportedChanges.length).toEqual(1) - expect(exportedChanges).toContainEqual({address: adr('A1'), value: 2}) - }) - - it('should export simple value change', () => { - const contentChanges = ContentChanges.empty() - - contentChanges.addChange(1, adr('A1')) - - const exportedChanges = contentChanges.exportChanges(simpleChangeExporter) - - expect(contentChanges.isEmpty()).toEqual(false) - expect(exportedChanges.length).toEqual(1) - expect(exportedChanges).toContainEqual({address: adr('A1'), value: 1}) - }) - - it('should export SimpleRangeValue change', () => { - const contentChanges = ContentChanges.empty() - - contentChanges.addChange(SimpleRangeValue.onlyValues([['foo', 'bar']]), adr('A1')) - - const exportedChanges = contentChanges.exportChanges(simpleChangeExporter) - - expect(exportedChanges.length).toEqual(1) - expect(exportedChanges).toContainEqual({address: adr('A1'), value: SimpleRangeValue.onlyValues([['foo', 'bar']])}) - }) - - it('should add all changes', () => { - const contentChanges = ContentChanges.empty() - contentChanges.addChange(1, adr('A1')) - - const otherChanges = ContentChanges.empty() - otherChanges.addChange(2, adr('A2')) - contentChanges.addAll(otherChanges) - - const exportedChanges = contentChanges.exportChanges(simpleChangeExporter) - expect(exportedChanges.length).toEqual(2) - expect(exportedChanges).toContainEqual({address: adr('A1'), value: 1}) - expect(exportedChanges).toContainEqual({address: adr('A2'), value: 2}) - }) - - it('should handle array change', () => { - const contentChanges = ContentChanges.empty() - contentChanges.addChange(SimpleRangeValue.onlyValues([[1, 2], ['foo', 'bar']]), adr('A1')) - - const exportedChanges = contentChanges.exportChanges(spreadRangeExporter) - - expect(exportedChanges.length).toEqual(4) - expect(exportedChanges).toContainEqual({address: adr('A1'), value: 1}) - expect(exportedChanges).toContainEqual({address: adr('B1'), value: 2}) - expect(exportedChanges).toContainEqual({address: adr('A2'), value: 'foo'}) - expect(exportedChanges).toContainEqual({address: adr('B2'), value: 'bar'}) - }) - - it('#1291 - array change should not delete neighboring non-overlapping changes', () => { - const contentChanges = ContentChanges.empty() - contentChanges.addChange(4, adr('B1')) - contentChanges.addChange(5, adr('C1')) - - const otherChanges = ContentChanges.empty() - otherChanges.addChange(SimpleRangeValue.onlyValues([[1], [2], [3]]), adr('A1')) - contentChanges.addAll(otherChanges) - - const exportedChanges = contentChanges.exportChanges(spreadRangeExporter) - expect(exportedChanges.length).toEqual(5) - expect(exportedChanges).toContainEqual({address: adr('A1'), value: 1}) - expect(exportedChanges).toContainEqual({address: adr('A2'), value: 2}) - expect(exportedChanges).toContainEqual({address: adr('A3'), value: 3}) - expect(exportedChanges).toContainEqual({address: adr('B1'), value: 4}) - expect(exportedChanges).toContainEqual({address: adr('C1'), value: 5}) - }) -}) diff --git a/test/unit/criterion.spec.ts b/test/unit/criterion.spec.ts deleted file mode 100644 index 9a3cf8617e..0000000000 --- a/test/unit/criterion.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import {CellError, ErrorType} from '../../src/Cell' -import {Config} from '../../src/Config' -import {DateTimeHelper} from '../../src/DateTimeHelper' -import {ArithmeticHelper} from '../../src/interpreter/ArithmeticHelper' -import {buildCriterion, CriterionBuilder, CriterionType} from '../../src/interpreter/Criterion' -import {NumberLiteralHelper} from '../../src/NumberLiteralHelper' - -describe('Criterion', () => { - const config = new Config() - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - const criterionBuilder = new CriterionBuilder(config) - it('greater than', () => { - expect(criterionBuilder.parseCriterion('>0', arithmeticHelper)).toEqual(buildCriterion(CriterionType.GREATER_THAN, 0)) - }) - - it('greater or equal than', () => { - expect(criterionBuilder.parseCriterion('>=0', arithmeticHelper)).toEqual(buildCriterion(CriterionType.GREATER_THAN_OR_EQUAL, 0)) - }) - - it('less than', () => { - expect(criterionBuilder.parseCriterion('<0', arithmeticHelper)).toEqual(buildCriterion(CriterionType.LESS_THAN, 0)) - }) - - it('less or equal than', () => { - expect(criterionBuilder.parseCriterion('<=0', arithmeticHelper)).toEqual(buildCriterion(CriterionType.LESS_THAN_OR_EQUAL, 0)) - }) - - it('not equal', () => { - expect(criterionBuilder.parseCriterion('<>0', arithmeticHelper)).toEqual(buildCriterion(CriterionType.NOT_EQUAL, 0)) - }) - - it('equal', () => { - expect(criterionBuilder.parseCriterion('=0', arithmeticHelper)).toEqual(buildCriterion(CriterionType.EQUAL, 0)) - }) - - it('works with bigger number', () => { - expect(criterionBuilder.parseCriterion('>=123', arithmeticHelper)).toEqual(buildCriterion(CriterionType.GREATER_THAN_OR_EQUAL, 123)) - }) - - it('works with negative numbers', () => { - expect(criterionBuilder.parseCriterion('>=-123', arithmeticHelper)).toEqual(buildCriterion(CriterionType.GREATER_THAN_OR_EQUAL, -123)) - }) - - it('works with floats', () => { - expect(criterionBuilder.parseCriterion('>=100.5', arithmeticHelper)).toEqual(buildCriterion(CriterionType.GREATER_THAN_OR_EQUAL, 100.5)) - }) - - it('works with scientific notation', () => { - expect(criterionBuilder.parseCriterion('>=1e5', arithmeticHelper)).toEqual(buildCriterion(CriterionType.GREATER_THAN_OR_EQUAL, 100000)) - }) - - it('works with strings', () => { - expect(criterionBuilder.parseCriterion('=asdf', arithmeticHelper)).toEqual(buildCriterion(CriterionType.EQUAL, 'asdf')) - }) - - it('works with empty string', () => { - expect(criterionBuilder.parseCriterion('=', arithmeticHelper)).toEqual(buildCriterion(CriterionType.EQUAL, null)) - }) - - it('null when unknown operator', () => { - expect(criterionBuilder.parseCriterion('><0', arithmeticHelper)).toEqual(undefined) - }) - - it('defaults to equal when unparsable string', () => { - expect(criterionBuilder.parseCriterion('$fdsa', arithmeticHelper)).toEqual(buildCriterion(CriterionType.EQUAL, '$fdsa')) - }) - - xit('defaults to equal when string with weirdly used operators', () => { - // not sure what should happen here - expect(criterionBuilder.parseCriterion('> { - expect(criterionBuilder.parseCriterion(new CellError(ErrorType.VALUE), arithmeticHelper)).toEqual(undefined) - }) - - it('works with criterion being just value', () => { - expect(criterionBuilder.parseCriterion(100.5, arithmeticHelper)).toEqual(buildCriterion(CriterionType.EQUAL, 100.5)) - }) -}) diff --git a/test/unit/crud-random.spec.ts b/test/unit/crud-random.spec.ts deleted file mode 100644 index cdea9913cd..0000000000 --- a/test/unit/crud-random.spec.ts +++ /dev/null @@ -1,277 +0,0 @@ -import {HyperFormula} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {verifyValues} from './testUtils' - -/** - * random int from global variable 'state' - */ - -const getInt = (function() { - let state = 1 - return function() { - state ^= state << 13 - state ^= state >> 17 - state ^= state << 5 - state &= 0x7FFFFFFF - return state - } -})() - -/** - * random float from global variable 'state' - */ -function getFloat(): number { - return getInt() / 0x80000000 -} - -/** - * boolean flag for outputing crud operations - */ -const outputLog = false - -/** - * random int in range between min and max - * - * @param min - * @param max - */ -function randomInteger(min: number, max: number) { - return Math.floor(getFloat() * (max - min)) + min -} - -type Pts = { x: number, y: number } - -type Rectangle = { topleft: Pts, bottomright: Pts } - -/** - * picks a random range as a subset of rectangle - * and builds a formula =SUM(range) - * @param engine - * @param rect - */ -function randomRange(engine: HyperFormula, rect: Rectangle): string { - const x1 = randomInteger(rect.topleft.x, rect.bottomright.x) - const x2 = randomInteger(rect.topleft.x, rect.bottomright.x) - const y1 = randomInteger(rect.topleft.y, rect.bottomright.y) - const y2 = randomInteger(rect.topleft.y, rect.bottomright.y) - const startAddress = engine.simpleCellAddressToString({ - sheet: 0, - col: Math.min(x1, x2), - row: Math.min(y1, y2), - }, 0) as string - const endAddress = engine.simpleCellAddressToString({ - sheet: 0, - col: Math.max(x1, x2), - row: Math.max(y1, y2) - }, 0) as string - return '=SUM(' + startAddress + ':' + endAddress + ')' -} - -function undoRedo(engine: HyperFormula) { - if (outputLog) { - console.log('engine.undo()') - } - engine.undo() - if (outputLog) { - console.log('engine.redo()') - } - engine.redo() -} - -/** - * Fills a rectangle of cells with random formula sums with a random ranges from another rectangle. - * @param engine - * @param rectFormulas - * @param rectValues - */ -function randomSums(engine: HyperFormula, rectFormulas: Rectangle, rectValues: Rectangle) { - allPts(rectFormulas).forEach((pts) => { - const formula = randomRange(engine, rectValues) - if (outputLog) { - console.log(`engine.setCellContents({sheet: 0, col: ${pts.x}, row: ${pts.y}}, '${formula}')`) - } - engine.setCellContents({sheet: 0, col: pts.x, row: pts.y}, formula) - undoRedo(engine) - }) -} - -/** - * Fills a rectangle of cells with random values. - * @param engine - * @param rectValues - */ -function randomVals(engine: HyperFormula, rectValues: Rectangle) { - allPts(rectValues).forEach((pts) => { - const val = randomInteger(-10, 10) - if (outputLog) { - console.log(`engine.setCellContents({sheet: 0, col:${pts.x}, row:${pts.y}}, ${val})`) - } - engine.setCellContents({sheet: 0, col: pts.x, row: pts.y}, val) - undoRedo(engine) - }) -} - -/** - * builds a rectangle from corner + X side length + Y side length - * @param pts - * @param sideX - * @param sideY - */ -function rectangleFromCorner(pts: Pts, sideX: number, sideY: number): Rectangle { - return {topleft: pts, bottomright: {x: pts.x + sideX, y: pts.y + sideY}} -} - -/** - * all addresses from a rectangle - * - * @param rect - */ -function allPts(rect: Rectangle): Pts[] { - const ret: Pts[] = [] - for (let x = rect.topleft.x; x < rect.bottomright.x; x++) { - for (let y = rect.topleft.y; y < rect.bottomright.y; y++) { - ret.push({x, y}) - } - } - return ret -} - -/** - * random shuffle of an array - * - * @param array - */ -function shuffleArray(array: T[]): T[] { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]] - } - return array -} - -/** - * swaps two rectangles in-place - * @param engine - * @param corner1 - * @param corner2 - * @param sideX - * @param sideY - */ -function swapTwoRectangles(engine: HyperFormula, pts1: Pts, pts2: Pts, sideX: number, sideY: number) { - if (outputLog) { - console.log(`engine.moveCells( AbsoluteCellRange.spanFrom({sheet: 0, col: ${pts1.x}, row: ${pts1.y}}, ${sideX}, ${sideY}), {sheet: 0, col: 1000, row: 1000})`) - } - engine.moveCells(AbsoluteCellRange.spanFrom({sheet: 0, col: pts1.x, row: pts1.y}, sideX, sideY), { - sheet: 0, - col: 1000, - row: 1000 - }) - undoRedo(engine) - if (outputLog) { - console.log(`engine.moveCells( AbsoluteCellRange.spanFrom({sheet: 0, col: ${pts2.x}, row: ${pts2.y}}, ${sideX}, ${sideY}), {sheet: 0, col: ${pts1.x}, row: ${pts1.y}})`) - } - engine.moveCells(AbsoluteCellRange.spanFrom({sheet: 0, col: pts2.x, row: pts2.y}, sideX, sideY), { - sheet: 0, - col: pts1.x, - row: pts1.y - }) - undoRedo(engine) - if (outputLog) { - console.log(`engine.moveCells( AbsoluteCellRange.spanFrom({sheet: 0, col: 1000, row: 1000}, ${sideX}, ${sideY}), {sheet: 0, col: ${pts2.x}, row: ${pts2.y}})`) - } - engine.moveCells(AbsoluteCellRange.spanFrom({sheet: 0, col: 1000, row: 1000}, sideX, sideY), { - sheet: 0, - col: pts2.x, - row: pts2.y - }) - undoRedo(engine) -} - -/** - * Empties the engine using .setCellContents() - * operates only on sheet: 0 - * - * @param engine - engine to be emptied - * @param rect - rectangle of adresses we expect nonempty cell to be in - * - * The outcome should be that there are no cells in the engine. - */ -function randomCleanup(engine: HyperFormula, rect: Rectangle) { - shuffleArray(allPts(rect)).forEach((pts) => { - if (outputLog) { - console.log(`engine.setCellContents({sheet: 0, col:${pts.x}, row:${pts.y}}, null)`) - } - engine.setCellContents({sheet: 0, col: pts.x, row: pts.y}, null) - undoRedo(engine) - } - ) -} - -describe('large psuedo-random test', () => { - it('growing rectangle + addRows + addColumns + removeRows + removeColumns should produce the same sheet as static sheet', () => { - const engine = HyperFormula.buildFromArray([]) - let sideX = 3 - const n = 4 - let sideY = 3 - for (let rep = 0; rep < 3; rep++) { - randomVals(engine, rectangleFromCorner({x: 0, y: 0}, sideX, sideY)) - verifyValues(engine) - for (let i = 0; i < n; i++) { - randomSums(engine, - rectangleFromCorner({x: sideX * (i + 1), y: 0}, sideX, sideY), - rectangleFromCorner({x: sideX * i, y: 0}, sideX, sideY) - ) - verifyValues(engine) - } - for (let i = 0; i < n; i++) { - randomSums(engine, - rectangleFromCorner({x: sideX * (i + 1), y: 0}, sideX, sideY), - rectangleFromCorner({x: 0, y: 0}, sideX * (i + 1), sideY) - ) - verifyValues(engine) - } - for (let i = 0; i < n; i++) { - const columnPositionToAdd = randomInteger(0, sideX * (n + 1) + 1) - if (outputLog) { - console.log(`engine.addColumns(0, [${columnPositionToAdd},2])`) - } - engine.addColumns(0, [columnPositionToAdd, 2]) - undoRedo(engine) - verifyValues(engine) - const columnPositionToRemove = randomInteger(0, sideX * (n + 1)) - if (outputLog) { - console.log(`engine.removeColumns(0, [${columnPositionToRemove},1])`) - } - engine.removeColumns(0, [columnPositionToRemove, 1]) - undoRedo(engine) - } - sideX += 1 - - const rowPositionToAdd = randomInteger(0, sideY + 1) - if (outputLog) { - console.log(`engine.addRows(0, [${rowPositionToAdd},2])`) - } - engine.addRows(0, [rowPositionToAdd, 2]) - undoRedo(engine) - sideY += 2 - verifyValues(engine) - const rowPositionToRemove = randomInteger(0, sideY) - if (outputLog) { - console.log(`engine.removeRows(0, [${rowPositionToRemove},1])`) - } - engine.removeRows(0, [rowPositionToRemove, 1]) - undoRedo(engine) - sideY -= 1 - verifyValues(engine) - const x1 = randomInteger(0, n * sideX) - const x2 = randomInteger(0, n * sideX) - const y1 = randomInteger(0, sideY) - const y2 = randomInteger(0, sideY) - swapTwoRectangles(engine, {x: x1, y: y1}, {x: x2, y: y2}, sideX, sideY) - verifyValues(engine) - } - randomCleanup(engine, rectangleFromCorner({x: 0, y: 0}, 2 * (n + 1) * sideX, 2 * sideY)) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) -}) diff --git a/test/unit/cruds/adding-columns-dependencies.spec.ts b/test/unit/cruds/adding-columns-dependencies.spec.ts deleted file mode 100644 index 17a2434057..0000000000 --- a/test/unit/cruds/adding-columns-dependencies.spec.ts +++ /dev/null @@ -1,533 +0,0 @@ -import {HyperFormula} from '../../../src' -import {EmptyCellVertex} from '../../../src/DependencyGraph' -import {CellAddress} from '../../../src/parser' - -import { - adr, - colEnd, - colStart, - expectEngineToBeTheSameAs, - extractReference, - extractRowRange, - rowEnd, - rowStart -} from '../testUtils' - -describe('Adding column, fixing dependency', () => { - describe('all in same sheet (case 1)', () => { - it('same sheet, case Aa, absolute column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '=$A1'], - ]) - - engine.addColumns(0, [1, 1]) - - expect(extractReference(engine, adr('C1'))).toEqual(CellAddress.absoluteCol(0, 0)) - }) - - it('same sheet, case Aa, absolute row and col', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '=$A$1'], - ]) - - engine.addColumns(0, [1, 1]) - - expect(extractReference(engine, adr('C1'))).toEqual(CellAddress.absolute(0, 0)) - }) - - it('same sheet, case Ab', () => { - const engine = HyperFormula.buildFromArray([ - ['=$B1' /* new col */, '42'], - ]) - - engine.addColumns(0, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.absoluteCol(2, 0)) - }) - - it('same sheet, case Raa', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '13', /* new col */ '42'], - ]) - - engine.addColumns(0, [2, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(1, 0)) - }) - - it('same sheet, case Rab', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '13', /* new col */ '=B1'], - ]) - - engine.addColumns(0, [2, 1]) - - expect(extractReference(engine, adr('D1'))).toEqual(CellAddress.relative(-2, 0)) - }) - - it('same sheet, case Rba', () => { - const engine = HyperFormula.buildFromArray([ - ['=C1', '13', /* new col */ '42'], - ]) - - engine.addColumns(0, [2, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(3, 0)) - }) - - it('same sheet, case Rbb', () => { - const engine = HyperFormula.buildFromArray([ - ['42', /* new col */ '=C1', '13'], - ]) - - engine.addColumns(0, [1, 1]) - - expect(extractReference(engine, adr('C1'))).toEqual(CellAddress.relative(1, 0)) - }) - - it('same sheet, same column', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '43'], - [null, '=B1'], - ]) - - engine.addColumns(0, [1, 1]) - - expect(extractReference(engine, adr('C2'))).toEqual(CellAddress.relative(0, -1)) - }) - }) - - describe('dependency address sheet different than formula address sheet and sheet in which we add columns (case 2)', () => { - it('absolute case', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - [ /* new col */ '=Sheet2!$A1'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.addColumns(0, [0, 1]) - - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.absoluteCol(0, 0, 1)) - }) - - it('R < r', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - [/* new col */ null, '=Sheet2!A1'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.addColumns(0, [0, 1]) - - expect(extractReference(engine, adr('C1'))).toEqual(CellAddress.relative(-2, 0, 1)) - }) - - it('r = R', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - [/* new col */ '=Sheet2!B1'], - ], - Sheet2: [ - [null, '1'], - ], - }) - - engine.addColumns(0, [0, 1]) - - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.relative(0, 0, 1)) - }) - - it('r < R', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1' /* new col */], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.addColumns(0, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - }) - }) - - describe('formula address sheet different than dependency address sheet and sheet in which we add columns (case 3)', () => { - it('dependency address before added column', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - [/* new col */ '1', '2'], - ], - Sheet2: [ - ['=Sheet1!B1'], - ], - }) - - engine.addColumns(0, [0, 1]) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(2, 0, 0)) - }) - - it('dependency address at added column', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - [/* new col */ '1'], - ], - Sheet2: [ - ['=Sheet1!A1'], - ], - }) - - engine.addColumns(0, [0, 1]) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(1, 0, 0)) - }) - - it('dependency address after added column', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1' /* new col */], - ], - Sheet2: [ - ['=Sheet1!A1'], - ], - }) - - engine.addColumns(0, [1, 1]) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(0, 0, 0)) - }) - }) - - describe('sheet where we add columns different than dependency address and formula address (case 4)', () => { - it('works', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=B1', '13'], - ], - Sheet2: [ - [null, /* new col */ '78'], - ], - }) - - engine.addColumns(1, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(1, 0)) - }) - }) - - describe('each sheet different (case 5)', () => { - it('works', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!B1', '13'], - ], - Sheet2: [ - [null, '78'], - ], - Sheet3: [ - [null, /* new col */ null], - ], - }) - - engine.addColumns(2, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(1, 0, 1)) - }) - }) -}) - -describe('Adding column, fixing ranges', () => { - it('insert column to empty range', () => { - const engine = HyperFormula.buildFromArray([ - [null, /* new col */ null, null], - ['=SUM(A1:C1)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).not.toBe(undefined) - - engine.addColumns(0, [1, 1]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('D1'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, null, null], - ['=SUM(A1:D1)'], - ])) - }) - - it('insert column in middle of range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '2', '3'], - ['=SUM(A1:C1)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).not.toBe(undefined) - - engine.addColumns(0, [1, 1]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('D1'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3'], - ['=SUM(A1:D1)'], - ])) - }) - - it('insert column before range', () => { - const engine = HyperFormula.buildFromArray([ - [/* new col */ '1', '2', '3'], - ['=SUM(A1:C1)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).not.toBe(undefined) - engine.addColumns(0, [0, 1]) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(adr('B1'), adr('D1'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1', '2', '3'], - [null, '=SUM(B1:D1)'], - ])) - }) - - it('insert column after range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3' /* new col */], - ['=SUM(A1:C1)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).not.toBe(undefined) - engine.addColumns(0, [3, 1]) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2', '3', null], - ['=SUM(A1:C1)'], - ])) - }) - - it('should insert new cell with edge to only one range at right', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', /* */ '3', '4'], - ['=SUM(A1:A1)', '=SUM(A1:B1)', /* */ '=SUM(A1:C1)', '=SUM(A1:D1)'], - ]) - - engine.addColumns(0, [2, 1]) - - const c1 = engine.addressMapping.getCell(adr('C1')) - const a1d1 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('D1')) - const a1e1 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('E1')) - - expect(engine.graph.existsEdge(c1!, a1d1)).toBe(true) - expect(engine.graph.existsEdge(c1!, a1e1)).toBe(true) - expect(engine.graph.adjacentNodesCount(c1!)).toBe(2) - }) - - it('range start in column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '3', '4'], - [null, /* */ '=SUM(B1:D1)'], - ]) - - engine.addColumns(0, [1, 1]) - - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(b1).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '4'], - [null, null, '=SUM(C1:E1)'], - ])) - }) - - it('range start before added column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '3', '4'], - [null, /* */ '=SUM(A1:D1)'], - ]) - - engine.addColumns(0, [1, 1]) - - const b1 = engine.addressMapping.getCell(adr('B1')) - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('E1')) - expect(b1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(b1!, range)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '4'], - [null, null, '=SUM(A1:E1)'], - ])) - }) - - it('range start after added column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '3', '4'], - [null, /* */ '=SUM(C1:D1)'], - ]) - - engine.addColumns(0, [1, 1]) - - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(b1).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '4'], - [null, null, '=SUM(D1:E1)'], - ])) - }) - - it('range end before added column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '3', '4'], - [null, /* */ '=SUM(A1:A1)'], - ]) - - engine.addColumns(0, [1, 1]) - - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(b1).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '4'], - [null, null, '=SUM(A1:A1)'], - ])) - }) - - it('range end in a added column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '3', '4'], - [null, /* */ '=SUM(A1:B1)'], - ]) - - engine.addColumns(0, [1, 1]) - - const b1 = engine.addressMapping.getCell(adr('B1')) - - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('C1')) - expect(b1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(b1!, range)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '4'], - [null, null, '=SUM(A1:C1)'], - ])) - }) - - it('range end after added column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '3', '4'], - [null, /* */ '=SUM(A1:C1)'], - ]) - - engine.addColumns(0, [1, 1]) - - const b1 = engine.addressMapping.getCell(adr('B1')) - - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('D1')) - expect(b1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(b1!, range)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '4'], - [null, null, '=SUM(A1:D1)'], - ])) - }) - - it('range start and end in an added column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '3', '4'], - [null, /* */ '=SUM(B1:B1)'], - ]) - - engine.addColumns(0, [1, 1]) - - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(b1).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '4'], - [null, null, '=SUM(C1:C1)'], - ])) - }) -}) - -describe('Adding column, fixing column ranges', () => { - it('insert column in middle of column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '2', '3', '=SUM(A:C)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('C'))).not.toBe(undefined) - - engine.addColumns(0, [1, 1]) - - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('C'))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('D'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3', '=SUM(A:D)'], - ])) - }) - - it('insert column before column range', () => { - const engine = HyperFormula.buildFromArray([ - [/* new col */ '1', '2', '3', '=SUM(A:C)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('C'))).not.toBe(undefined) - engine.addColumns(0, [0, 1]) - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('C'))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(colStart('B'), colEnd('D'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1', '2', '3', '=SUM(B:D)'], - ])) - }) - - it('insert column after column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3' /* new col */, '=SUM(A:C)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('C'))).not.toBe(undefined) - engine.addColumns(0, [3, 1]) - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('C'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2', '3', null, '=SUM(A:C)'], - ])) - }) -}) - -describe('Adding column, row range', () => { - it('row range should not be affected', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /*new column */ '2', '3'], - ['4', /*new column */ '5', '6'], - [null, /*new column */null, '=SUM(1:2)'], - ]) - - engine.addColumns(0, [1, 1]) - - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(2))).not.toBe(undefined) - const rowRange = extractRowRange(engine, adr('D3')) - expect(rowRange.start).toEqual(rowStart(1)) - expect(rowRange.end).toEqual(rowEnd(2)) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null, '2', '3'], - ['4', null, '5', '6'], - [null, null, null, '=SUM(1:2)'], - ])) - }) -}) diff --git a/test/unit/cruds/adding-columns.spec.ts b/test/unit/cruds/adding-columns.spec.ts deleted file mode 100644 index feded11825..0000000000 --- a/test/unit/cruds/adding-columns.spec.ts +++ /dev/null @@ -1,473 +0,0 @@ -import { - AlwaysDense, - ExportedCellChange, - HyperFormula, - SheetSizeLimitExceededError, - ErrorType, -} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {Config} from '../../../src/Config' -import {ArrayFormulaVertex, ScalarFormulaVertex} from '../../../src/DependencyGraph' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import { - adr, - expectArrayWithSameContent, - expectEngineToBeTheSameAs, - extractMatrixRange, - extractRange -} from '../testUtils' -import { ErrorMessage } from '../../../src/error-message' -import { detailedError } from '../testUtils' - -describe('Adding column - checking if its possible', () => { - it('no if starting column is negative', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(0, [-1, 1])).toEqual(false) - }) - - it('no if starting column is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(0, [1.5, 1])).toEqual(false) - }) - - it('no if starting column is NaN/Infinity', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(0, [NaN, 1])).toEqual(false) - expect(engine.isItPossibleToAddColumns(0, [Infinity, 1])).toEqual(false) - expect(engine.isItPossibleToAddColumns(0, [-Infinity, 1])).toEqual(false) - }) - - it('no if number of columns is not positive', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(0, [0, 0])).toEqual(false) - }) - - it('no if number of columns is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(0, [0, 1.5])).toEqual(false) - }) - - it('no if number of columns is NaN/Infinity', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(0, [0, NaN])).toEqual(false) - expect(engine.isItPossibleToAddColumns(0, [0, Infinity])).toEqual(false) - expect(engine.isItPossibleToAddColumns(0, [0, -Infinity])).toEqual(false) - }) - - it('no if sheet does not exist', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddColumns(1.5, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddColumns(-1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddColumns(NaN, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddColumns(Infinity, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddColumns(-Infinity, [0, 1])).toEqual(false) - }) - - it('no if adding column would exceed sheet size limit', () => { - const engine = HyperFormula.buildFromArray([ - Array(Config.defaultConfig.maxColumns - 1).fill('') - ]) - - expect(engine.isItPossibleToAddColumns(0, [0, 2])).toEqual(false) - expect(engine.isItPossibleToAddColumns(0, [0, 1], [5, 1])).toEqual(false) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddColumns(0, [0, 1])).toEqual(true) - }) -}) - -describe('Adding column - matrix check', () => { - it('should be possible to add a row crossing matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', 'foo', 'bar'], - ['3', '4', '=TRANSPOSE(A1:B3)'], - ['5', '6'], - ], {chooseAddressMappingPolicy: new AlwaysDense()}) - - engine.addColumns(0, [3, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2', 'foo', null, 'bar'], - ['3', '4', '=TRANSPOSE(A1:B3)'], - ['5', '6'] - ])) - }) - - it('should adjust matrix address mapping when adding multiple columns', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', 'foo', 'bar'], - ['3', '4', '=TRANSPOSE(A1:B3)'], - ['5', '6'], - ], {chooseAddressMappingPolicy: new AlwaysDense()}) - - engine.addColumns(0, [3, 3]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2', 'foo', null, null, null, 'bar'], - ['3', '4', '=TRANSPOSE(A1:B3)'], - ['5', '6'] - ])) - }) - - it('should result in cell errors when attempting to use nonscalars', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', 'foo', 'bar'], - ['3', '4', '=TRANSPOSE(A1:B3)'], - ['5', '=A2:A3'] - ], { chooseAddressMappingPolicy: new AlwaysDense() }) - - engine.addColumns(0, [3, 1]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(2) - expect(engine.getCellValue(adr('C1'))).toBe('foo') - expect(engine.getCellValue(adr('D1'))).toBe(null) - expect(engine.getCellValue(adr('E1'))).toBe('bar') - - expect(engine.getCellValue(adr('A2'))).toBe(3) - expect(engine.getCellValue(adr('B2'))).toBe(4) - expect(engine.getCellValue(adr('C2'))).toBe(1) - expect(engine.getCellValue(adr('D2'))).toBe(3) - expect(engine.getCellValue(adr('E2'))).toBe(5) - - expect(engine.getCellValue(adr('A3'))).toBe(5) - expect(engine.getCellValue(adr('B3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('C3'))).toBe(2) - expect(engine.getCellValue(adr('D3'))).toBe(4) - expect(engine.getCellValue(adr('E3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('should be possible to add row right before matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(C1:D2)', undefined, '1', '2'], - [undefined, undefined, '3', '4'], - ]) - - engine.addColumns(0, [0, 1]) - - expect(engine.getCellValue(adr('A1'))).toBe(null) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(3) - expect(engine.getCellValue(adr('D1'))).toEqual(1) - }) - - it('should be possible to add row right after matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(C1:D2)', undefined, '1', '2'], - [undefined, undefined, '3', '4'], - ]) - - engine.addColumns(0, [2, 1]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(engine.getCellValue(adr('C1'))).toBe(null) - expect(engine.getCellValue(adr('D1'))).toEqual(1) - }) -}) - -describe('Adding column - reevaluation', () => { - it('reevaluates cells', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '2', '=COUNTBLANK(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(0) - engine.addColumns(0, [1, 1]) - expect(engine.getCellValue(adr('D1'))).toEqual(1) - }) - - it('dont reevaluate everything', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '2', '=COUNTBLANK(A1:B1)'], - ['=SUM(A1:A1)'], - ]) - const c1 = engine.addressMapping.getCell(adr('C1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const a2setCellValueSpy = spyOn(a2 as any, 'setCellValue') - - engine.addColumns(0, [1, 1]) - - expect(a2setCellValueSpy).not.toHaveBeenCalled() - expect(c1setCellValueSpy).toHaveBeenCalled() - }) - - it('reevaluates cells which are dependent on structure changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* */ '2', '=COLUMNS(A1:B1)'], - ]) - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - - engine.addColumns(0, [1, 1]) - - expect(c1setCellValueSpy).toHaveBeenCalled() - expect(extractRange(engine, adr('D1'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('C1'))) - }) - - it('returns changed values', () => { - const engine = HyperFormula.buildFromArray([ - /* */ - ['1', '2', '=COLUMNS(A1:B1)'], - ]) - - const changes = engine.addColumns(0, [1, 1]) - - expect(changes.length).toBe(1) - expect(changes).toContainEqual(new ExportedCellChange(adr('D1'), 3)) - }) -}) - -describe('Adding column - ScalarFormulaVertex#address update', () => { - it('updates addresses in formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '=A1'], - ]) - - engine.addColumns(0, [1, 1]) - - const c1 = engine.addressMapping.getCell(adr('C1')) as ScalarFormulaVertex - expect(c1).toBeInstanceOf(ScalarFormulaVertex) - expect(c1.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('C1')) - }) -}) - -describe('Adding column - address mapping', () => { - it('verify sheet dimensions', () => { - const engine = HyperFormula.buildFromArray([ - ['1', /* new col */ '=A1'], - ]) - - engine.addColumns(0, [1, 1]) - - expect(engine.getSheetDimensions(0)).toEqual({ - width: 3, - height: 1, - }) - }) -}) - -describe('different sheet', () => { - it('adding row in different sheet but same row as formula should not update formula address', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], - ], - Sheet2: [ - ['=Sheet1!A1'], - ], - }) - - engine.addColumns(0, [0, 1]) - - const formulaVertex = engine.addressMapping.getCell(adr('A1', 1)) as ScalarFormulaVertex - - expect(formulaVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A1', 1)) - formulaVertex.getFormula(engine.lazilyTransformingAstService) // force transformations to be applied - expect(formulaVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A1', 1)) - }) -}) - -describe('Adding column - sheet dimensions', () => { - it('should do nothing when adding column outside effective sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const recalcSpy = spyOn(engine.evaluator as any, 'partialRun') - engine.addColumns(0, [1, 1]) - engine.addColumns(0, [10, 15]) - - expect(recalcSpy).not.toHaveBeenCalled() - expect(engine.getSheetDimensions(0)).toEqual({ - width: 1, - height: 1, - }) - }) - - it('should throw error when trying to expand sheet beyond limits', () => { - const engine = HyperFormula.buildFromArray([ - Array(Config.defaultConfig.maxColumns - 1).fill('') - ]) - - expect(() => { - engine.addColumns(0, [0, 2]) - }).toThrow(new SheetSizeLimitExceededError()) - - expect(() => { - engine.addColumns(0, [0, 1], [5, 1]) - }).toThrow(new SheetSizeLimitExceededError()) - }) -}) - -describe('Adding column - column index', () => { - it('should update column index when adding row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=VLOOKUP(1, A1:A1, 1, TRUE())'], - ], {useColumnIndex: true}) - const index = (engine.columnSearch as ColumnIndex) - - expectArrayWithSameContent([0], index.getValueIndex(0, 0, 1).index) - - engine.addColumns(0, [0, 1]) - - expectArrayWithSameContent([], index.getValueIndex(0, 0, 1).index) - expectArrayWithSameContent([0], index.getValueIndex(0, 1, 1).index) - }) -}) - -describe('Adding column - arrays', () => { - it('should be possible to add column before array', () => { - const engine = HyperFormula.buildFromArray([ - ['=-A3:C4', null, null, 'foo'], - ], {useArrayArithmetic: true}) - - engine.addColumns(0, [0, 1]) - - const expected = HyperFormula.buildFromArray([ - [null, '=-B3:D4', null, null, 'foo'], - ], {useArrayArithmetic: true}) - - expectEngineToBeTheSameAs(engine, expected) - }) - - it('adding column across array should not change array', () => { - const engine = HyperFormula.buildFromArray([ - [null, null, null, '=-A1:C1', null, null, 'foo'] - ], {useArrayArithmetic: true}) - - engine.addColumns(0, [4, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, null, '=-A1:C1', null, null, null, 'foo'] - ], {useArrayArithmetic: true})) - }) - - it('adding column should expand dependent array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=TRANSPOSE(A1:B2)'], - [3, 4], - ], {useArrayArithmetic: true}) - - engine.addColumns(0, [1, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, null, 2, '=TRANSPOSE(A1:C2)'], - [3, null, 4], - ], {useArrayArithmetic: true})) - }) - - it('undo add column with dependent array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=TRANSPOSE(A1:B2)'], - [3, 4], - ], {useArrayArithmetic: true}) - - engine.addColumns(0, [1, 1]) - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2, '=TRANSPOSE(A1:B2)'], - [3, 4], - ], {useArrayArithmetic: true})) - }) - - it('ArrayFormulaVertex#formula should be updated', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=TRANSPOSE(A1:B2)'], - [3, 4], - ]) - - engine.addColumns(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('D1'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('C2'))) - }) - - it('ArrayFormulaVertex#formula should be updated when different sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['3', '4'], - ], - Sheet2: [ - ['=TRANSPOSE(Sheet1!A1:B2)'], - ], - }) - - engine.addColumns(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('A1'), adr('C2'))) - }) - - it('ArrayFormulaVertex#address should be updated', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=TRANSPOSE(A1:B2)'], - [3, 4], - ]) - - engine.addColumns(0, [1, 1]) - - const matrixVertex = engine.addressMapping.getCell(adr('D1')) as ArrayFormulaVertex - expect(matrixVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('D1')) - }) -}) - -describe('Adding column where there are empty rows in the address mapping (DenseStrategy) - issue #1406', () => { - it('should not throw errors (simple case)', () => { - const hf = HyperFormula.buildFromArray([], { chooseAddressMappingPolicy: new AlwaysDense() }) - - hf.setCellContents({ row: 1, col: 0, sheet: 0 }, 'test') - hf.addColumns(0, [0, 1]) //one column added index [row, amount] - added - - expect(hf.getSheetSerialized(0)).toEqual([ [], [null, 'test'] ]) - }) - - it('should not throw errors (stackblitz reproduction)', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: 'gpl-v3', - chooseAddressMappingPolicy: new AlwaysDense() - }) - - const sheetName = hf.addSheet('main') - const sheetId = hf.getSheetId(sheetName)! - - hf.setCellContents( - { row: 0, col: 0, sheet: sheetId }, - [ - ['test', null, undefined, 4], - [null, 3, '=ISBLANK(B1)'], - ] - ) - - hf.addRows(0, [2, 1]) - hf.addRows(0, [3, 1]) - hf.setCellContents( - { row: 3, col: 0, sheet: sheetId }, - 'will-it-break?' - ) - hf.addColumns(0, [0, 1]) - - expect(hf.getSheetSerialized(0)).toEqual([ - [null, 'test', null, null, 4], - [null, null, 3, '=ISBLANK(C1)'], - [], - [null, 'will-it-break?'], - ]) - }) -}) diff --git a/test/unit/cruds/adding-row-dependencies.spec.ts b/test/unit/cruds/adding-row-dependencies.spec.ts deleted file mode 100644 index 812c53dc75..0000000000 --- a/test/unit/cruds/adding-row-dependencies.spec.ts +++ /dev/null @@ -1,646 +0,0 @@ -import {HyperFormula} from '../../../src' -import {EmptyCellVertex} from '../../../src/DependencyGraph' -import {CellAddress} from '../../../src/parser' -import {adr, colEnd, colStart, expectEngineToBeTheSameAs, extractReference, rowEnd, rowStart} from '../testUtils' - -describe('Adding row - fixing dependencies', () => { - describe('all in same sheet (case 1)', () => { - it('same sheet, case Aa, absolute row', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - // new row - ['=A$1'], - ]) - - engine.addRows(0, [1, 1]) - - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.absoluteRow(0, 0)) - }) - - it('same sheet, case Aa, absolute row and col', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - // new row - ['=$A$1'], - ]) - - engine.addRows(0, [1, 1]) - - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.absolute(0, 0)) - }) - - it('same sheet, case Ab', () => { - const engine = HyperFormula.buildFromArray([ - ['=A$2'], - // new row - ['42'], - ]) - - engine.addRows(0, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.absoluteRow(0, 2)) - }) - - it('same sheet, case Raa', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2'], - ['13'], - // new row - ['42'], - ]) - - engine.addRows(0, [2, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 1)) - }) - - it('same sheet, case Rab', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['13'], - // new row - ['=A2'], - ]) - - engine.addRows(0, [2, 1]) - - expect(extractReference(engine, adr('A4'))).toEqual(CellAddress.relative(0, -2)) - }) - - it('same sheet, case Rba', () => { - const engine = HyperFormula.buildFromArray([ - ['=A3'], - ['13'], - // new row - ['42'], - ]) - - engine.addRows(0, [2, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 3)) - }) - - it('same sheet, case Rbb', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - // new row - ['=A3'], - ['13'], - ]) - - engine.addRows(0, [1, 1]) - - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.relative(0, 1)) - }) - - it('same sheet, same row', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['43', '=A2'], - ]) - - engine.addRows(0, [1, 1]) - - expect(extractReference(engine, adr('B3'))).toEqual(CellAddress.relative(-1, 0)) - }) - }) - - describe('dependency address sheet different than formula address sheet and sheet in which we add rows (case 2)', () => { - it('absolute case', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - // new row - ['=Sheet2!A$1'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.addRows(0, [0, 1]) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.absoluteRow(0, 0, 1)) - }) - - it('R < r', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - // new row - [null], - ['=Sheet2!A1'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.addRows(0, [0, 1]) - - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.relative(0, -2, 1)) - }) - - it('r = R', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - // new row - ['=Sheet2!A2'], - ], - Sheet2: [ - [null], - ['1'], - ], - }) - - engine.addRows(0, [0, 1]) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.relative(0, 0, 1)) - }) - - it('r < R', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1'], - // new row - ], - Sheet2: [ - ['1'], - ], - }) - - engine.addRows(0, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - }) - }) - - describe('formula address sheet different than dependency address sheet and sheet in which we add rows (case 3)', () => { - it('dependency address before added row', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - // new row - ['1'], - ['2'], - ], - Sheet2: [ - ['=Sheet1!A2'], - ], - }) - - engine.addRows(0, [0, 1]) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(0, 2, 0)) - }) - - it('dependency address at added row', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - // new row - ['1'], - ], - Sheet2: [ - ['=Sheet1!A1'], - ], - }) - - engine.addRows(0, [0, 1]) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(0, 1, 0)) - }) - - it('dependency address after added row', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], - // new row - ], - Sheet2: [ - ['=Sheet1!A1'], - ], - }) - - engine.addRows(0, [1, 1]) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(0, 0, 0)) - }) - }) - - describe('sheet where we add rows different than dependency address and formula address (case 4)', () => { - it('works', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=A2'], - ['13'], - ], - Sheet2: [ - [null], - // new row - ['78'], - ], - }) - - engine.addRows(1, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 1)) - }) - }) - - describe('each sheet different (case 5)', () => { - it('works', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A2'], - ['13'], - ], - Sheet2: [ - [null], - ['78'], - ], - Sheet3: [ - [null], - // new row - [null], - ], - }) - - engine.addRows(2, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 1, 1)) - }) - }) -}) - -describe('Adding row, ranges', () => { - it('insert row in middle of range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A3)'], - // new row - ['2', null], - ['3', null], - ]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('A3'))).not.toBe(undefined) - engine.addRows(0, [1, 1]) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('A3'))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('A4'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A4)'], - [null, null], - ['2', null], - ['3', null], - ])) - }) - - it('insert row above range', () => { - const engine = HyperFormula.buildFromArray([ - // new row - ['1', '=SUM(A1:A3)'], - ['2', null], - ['3', null], - ]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('A3'))).not.toBe(undefined) - engine.addRows(0, [0, 1]) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('A3'))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(adr('A2'), adr('A4'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null], - ['1', '=SUM(A2:A4)'], - ['2', null], - ['3', null], - ])) - }) - - it('insert row below range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A3)'], - ['2', null], - ['3', null], - // new row - ]) - - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('A3'))).not.toBe(undefined) - engine.addRows(0, [3, 1]) - expect(engine.rangeMapping.getRangeVertex(adr('A1'), adr('A3'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A3)'], - ['2', null], - ['3', null], - [null, null], - ])) - }) - - it('should insert new cell with edge to all ranges below', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A1)'], - ['2', '=SUM(A1:A2)'], - // new row - ['3', '=SUM(A1:A3)'], - ['4', '=SUM(A1:A4)'], - ]) - - engine.addRows(0, [2, 1]) - - const a4 = engine.addressMapping.getCell(adr('A4')) - const a3 = engine.addressMapping.getCell(adr('A3')) - const a2 = engine.addressMapping.getCell(adr('A2')) - const a1a4 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A4')) // A1:A4 - const a1a3 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) // A1:A4 - const a1a2 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) // A1:A4 - - expect(engine.graph.existsEdge(a4!, a1a4)).toBe(true) - expect(engine.graph.existsEdge(a3!, a1a3)).toBe(true) - expect(engine.graph.existsEdge(a2!, a1a2)).toBe(true) - expect(engine.graph.adjacentNodesCount(a4!)).toBe(1) - expect(engine.graph.adjacentNodesCount(a3!)).toBe(1) - expect(engine.graph.adjacentNodesCount(a2!)).toBe(1) - }) - - it('should insert new cell with edge to only one range below, shifted by 1', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - ['2', '=SUM(A1:A1)'], - ['3', '=SUM(A1:A2)'], - // new row - ['4', '=SUM(A1:A3)'], - ]) - - engine.addRows(0, [3, 1]) - - const a4 = engine.addressMapping.getCell(adr('A4')) - expect(a4).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - ['2', '=SUM(A1:A1)'], - ['3', '=SUM(A1:A2)'], - [null, null], - ['4', '=SUM(A1:A3)'], - ])) - }) - - it('range start in row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - // new row - ['2', '=SUM(A2:A4)'], - ['3', null], - ['4', null], - ]) - - engine.addRows(0, [1, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(a2).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - [null, null], - ['2', '=SUM(A3:A5)'], - ['3', null], - ['4', null], - ])) - }) - - it('range start above row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - // new row - ['2', '=SUM(A1:A4)'], - ['3', null], - ['4', null], - ]) - - engine.addRows(0, [1, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A5')) - expect(a2).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a2!, range)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - [null, null], - ['2', '=SUM(A1:A5)'], - ['3', null], - ['4', null], - ])) - }) - - it('range start below row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - // new row - ['2', '=SUM(A3:A4)'], - ['3', null], - ['4', null], - ]) - - engine.addRows(0, [1, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(a2).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - [null, null], - ['2', '=SUM(A4:A5)'], - ['3', null], - ['4', null], - ])) - }) - - it('range end above row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - // new row - ['2', '=SUM(A1:A1)'], - ['3', null], - ['4', null], - ]) - - engine.addRows(0, [1, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(a2).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - [null, null], - ['2', '=SUM(A1:A1)'], - ['3', null], - ['4', null], - ])) - }) - - it('range end in a row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - // new row - ['2', '=SUM(A1:A2)'], - ['3', null], - ['4', null], - ]) - - engine.addRows(0, [1, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) - expect(a2).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a2!, range)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - [null, null], - ['2', '=SUM(A1:A3)'], - ['3', null], - ['4', null], - ])) - }) - - it('range end below row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - // new row - ['2', '=SUM(A1:A3)'], - ['3', null], - ['4', null], - ]) - - engine.addRows(0, [1, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A4')) - expect(a2).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a2!, range)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - [null, null], - ['2', '=SUM(A1:A4)'], - ['3', null], - ['4', null], - ])) - }) - - it('range start and end in a row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - // new row - ['2', '=SUM(A2:A2)'], - ['3', null], - ['4', null], - ]) - - engine.addRows(0, [1, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(a2).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', null], - [null, null], - ['2', '=SUM(A3:A3)'], - ['3', null], - ['4', null], - ])) - }) -}) - -describe('Adding row, column range', () => { - it('column range should not be affected', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '=SUM(A:B)'], - // new row - ['2', '2'], - ['3', '3'], - ]) - - engine.addRows(0, [1, 1]) - - expect(engine.rangeMapping.getRangeVertex(colStart('A'), colEnd('B'))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '1', '=SUM(A:B)'], - [null, null], - ['2', '2'], - ['3', '3'], - ])) - }) -}) - -describe('Adding row, fixing row ranges', () => { - it('insert row in middle of row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - /* new row */ - ['2'], - ['3'], - ['=SUM(1:3)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(3))).not.toBe(undefined) - - engine.addRows(0, [1, 1]) - - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(3))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(4))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1'], - [null], - ['2'], - ['3'], - ['=SUM(1:4)'], - ])) - }) - - it('insert row before row range', () => { - const engine = HyperFormula.buildFromArray([ - /* new row */ - ['1'], - ['2'], - ['3'], - ['=SUM(1:3)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(3))).not.toBe(undefined) - engine.addRows(0, [0, 1]) - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(3))).toBe(undefined) - expect(engine.rangeMapping.getRangeVertex(rowStart(2), rowEnd(4))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null], - ['1'], - ['2'], - ['3'], - ['=SUM(2:4)'], - ])) - }) - - it('insert row after row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - /* new row */ - ['=SUM(1:3)'], - ]) - - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(3))).not.toBe(undefined) - engine.addRows(0, [3, 1]) - expect(engine.rangeMapping.getRangeVertex(rowStart(1), rowEnd(3))).not.toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - [null], - ['=SUM(1:3)'], - ])) - }) -}) diff --git a/test/unit/cruds/adding-row.spec.ts b/test/unit/cruds/adding-row.spec.ts deleted file mode 100644 index 45d0a8651e..0000000000 --- a/test/unit/cruds/adding-row.spec.ts +++ /dev/null @@ -1,481 +0,0 @@ -import {ExportedCellChange, HyperFormula, SheetSizeLimitExceededError} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {Config} from '../../../src/Config' -import {ArrayFormulaVertex, ScalarFormulaVertex} from '../../../src/DependencyGraph' -import {AlwaysDense} from '../../../src/DependencyGraph/AddressMapping/ChooseAddressMappingPolicy' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import {adr, expectArrayWithSameContent, expectEngineToBeTheSameAs, extractMatrixRange} from '../testUtils' - -describe('Adding row - checking if its possible', () => { - it('no if starting row is negative', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(0, [-1, 1])).toEqual(false) - }) - - it('no if starting row is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(0, [1.5, 1])).toEqual(false) - }) - - it('no if starting row is NaN', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(0, [NaN, 1])).toEqual(false) - expect(engine.isItPossibleToAddRows(0, [Infinity, 1])).toEqual(false) - expect(engine.isItPossibleToAddRows(0, [-Infinity, 1])).toEqual(false) - }) - - it('no if number of rows is not positive', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(0, [0, 0])).toEqual(false) - }) - - it('no if number of rows is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(0, [0, 1.5])).toEqual(false) - }) - - it('no if number of rows is NaN', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(0, [0, NaN])).toEqual(false) - expect(engine.isItPossibleToAddRows(0, [0, Infinity])).toEqual(false) - expect(engine.isItPossibleToAddRows(0, [0, -Infinity])).toEqual(false) - }) - - it('no if sheet does not exist', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddRows(1.5, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddRows(-1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddRows(NaN, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddRows(Infinity, [0, 1])).toEqual(false) - expect(engine.isItPossibleToAddRows(-Infinity, [0, 1])).toEqual(false) - }) - - it('no if adding row would exceed sheet size limit', () => { - const engine = HyperFormula.buildFromArray( - Array(Config.defaultConfig.maxRows - 1).fill(['']) - ) - - expect(engine.isItPossibleToAddRows(0, [0, 2])).toEqual(false) - expect(engine.isItPossibleToAddRows(0, [0, 1], [5, 1])).toEqual(false) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToAddRows(0, [0, 1])).toEqual(true) - }) -}) - -describe('Adding row - matrix', () => { - it('should be possible to add row crossing matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['foo', '=TRANSPOSE(A1:C2)'], - ['bar'], - ], {chooseAddressMappingPolicy: new AlwaysDense()}) - - engine.addRows(0, [3, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['foo', '=TRANSPOSE(A1:C2)'], - [null], - ['bar'], - ])) - }) - - it('should adjust matrix address mapping when adding multiple rows', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['foo', '=TRANSPOSE(A1:C2)'], - ['bar'], - ], {chooseAddressMappingPolicy: new AlwaysDense()}) - - engine.addRows(0, [3, 3]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['foo', '=TRANSPOSE(A1:C2)'], - [null], - [null], - [null], - ['bar'], - ])) - }) - - it('should be possible to add row right above matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(A3:B4)'], - [], - ['1', '2'], - ['3', '4'], - ]) - - engine.addRows(0, [0, 1]) - - expect(engine.getCellValue(adr('A1'))).toBe(null) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('B2'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('should be possible to add row right after matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(A3:B4)'], - [], - ['1', '2'], - ['3', '4'], - ]) - - engine.addRows(0, [2, 1]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toBe(null) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) -}) - -describe('Adding row - reevaluation', () => { - it('reevaluates cells', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=COUNTBLANK(A1:A2)'], - // new row - ['2'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - engine.addRows(0, [1, 1]) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - }) - - it('dont reevaluate everything', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=COUNTBLANK(A1:A2)', '=SUM(A1:A1)'], - // new row - ['2'], - ]) - const b1 = engine.addressMapping.getCell(adr('B1')) - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const b1setCellValueSpy = spyOn(b1 as any, 'setCellValue') - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - - engine.addRows(0, [1, 1]) - - expect(b1setCellValueSpy).toHaveBeenCalled() - expect(c1setCellValueSpy).not.toHaveBeenCalled() - }) - - it('reevaluates cells which are dependent on structure changes', () => { - const engine = HyperFormula.buildFromArray([ - /* */ - ['1', '2', '=COLUMNS(A1:B1)'], - ]) - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - - engine.addRows(0, [0, 1]) - - expect(c1setCellValueSpy).toHaveBeenCalled() - }) - - describe('returns array of changes', () => { - it('not including a value cell that was shifted due to adding a row before it', () => { - const engine = HyperFormula.buildFromArray([['1'],]) - - const changes = engine.addRows(0, [0, 1]) - expect(changes.length).toBe(0) - }) - - it('not including a formula cell that was shifted due to adding a row before it, but its value is the same', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - ['=SUM(A1:B1)'], - ]) - - const changes = engine.addRows(0, [1, 1]) - expect(changes.length).toBe(0) - }) - - it('not including a formula cell in which the cell references changed (due to the row shift), but its value is the same', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(A2:B2)'], - [1, 2], - ]) - - const changes = engine.addRows(0, [1, 1]) - expect(changes.length).toBe(0) - }) - - it('including a formula cell that was re-evaluated to different result', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2', '=COUNTBLANK(A1:A2)'], - ]) - - const changes = engine.addRows(0, [1, 1]) - - expect(changes.length).toBe(1) - expect(changes).toContainEqual(new ExportedCellChange(adr('B3'), 1)) - }) - - it('not including a formula cell that was re-evaluated to same result', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2', '=ROWS(A1:A2)-COUNTBLANK(A1:A2)'], - ]) - - expect(engine.getCellValue(adr('B2'))).toBe(2) - - const changes = engine.addRows(0, [1, 1]) - - expect(changes.length).toBe(0) - }) - }) -}) - -describe('Adding row - ScalarFormulaVertex#address update', () => { - it('insert row, formula vertex address shifted', () => { - const engine = HyperFormula.buildFromArray([ - // new row - ['=SUM(1, 2)'], - ]) - - let vertex = engine.addressMapping.getCell(adr('A1')) as ScalarFormulaVertex - expect(vertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A1')) - engine.addRows(0, [0, 1]) - vertex = engine.addressMapping.getCell(adr('A2')) as ScalarFormulaVertex - expect(vertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A2')) - }) - - it('adding row in different sheet but same row as formula should not update formula address', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - // new row - ['1'], - ], - Sheet2: [ - ['=Sheet1!A1'], - ], - }) - - engine.addRows(0, [0, 1]) - - const formulaVertex = engine.addressMapping.getCell(adr('A1', 1)) as ScalarFormulaVertex - - expect(formulaVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A1', 1)) - formulaVertex.getFormula(engine.lazilyTransformingAstService) // force transformations to be applied - expect(formulaVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A1', 1)) - }) -}) - -describe('Adding row - address mapping', () => { - it('verify sheet dimensions', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - // new row - ['2'], - ]) - - engine.addRows(0, [1, 1]) - - expect(engine.getSheetDimensions(0)).toEqual({ - width: 1, - height: 3, - }) - }) - - it('addRows() leaves the engine in a valid state so other operations are possible afterwards', () => { - const hfInstance = HyperFormula.buildFromArray([['=A1+B5']]) - hfInstance.addRows(0, [1, 1]) - hfInstance.setCellContents({ sheet: 0, col: 0, row: 1 }, '=A1+B5') - hfInstance.setSheetContent(0, [['=A1+B5'], ['=A1+B5']]) - expect(hfInstance.getSheetSerialized(0)).toEqual([['=A1+B5'], ['=A1+B5']]) - }) - - it('addRows() leaves the engine in a valid state so other operations are possible afterwards (2)', () => { - const hfInstance = HyperFormula.buildFromArray([['=A1+B5']]) - hfInstance.addRows(0, [1, 1]) - hfInstance.setCellContents({ sheet: 0, col: 0, row: 1 }, '=A1+B5') - hfInstance.setSheetContent(0, [['=A1+B5'], ['=A1+B5']]) - expect(hfInstance.getSheetSerialized(0)).toEqual([['=A1+B5'], ['=A1+B5']]) - }) -}) - -describe('Adding row - sheet dimensions', () => { - it('should do nothing when adding row outside effective sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - // new row - ]) - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const recalcSpy = spyOn(engine.evaluator as any, 'partialRun') - engine.addRows(0, [1, 1]) - engine.addRows(0, [10, 15]) - - expect(recalcSpy).not.toHaveBeenCalled() - expect(engine.getSheetDimensions(0)).toEqual({ - width: 1, - height: 1, - }) - }) - - it('should throw error when trying to expand sheet beyond limits', () => { - const engine = HyperFormula.buildFromArray(Array(Config.defaultConfig.maxRows - 1).fill([''])) - - expect(() => { - engine.addRows(0, [0, 2]) - }).toThrow(new SheetSizeLimitExceededError()) - - expect(() => { - engine.addRows(0, [0, 1], [5, 1]) - }).toThrow(new SheetSizeLimitExceededError()) - }) -}) - -describe('Adding row - column index', () => { - it('should update column index when adding row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=VLOOKUP(2, A1:A10, 1, TRUE())'], - ['2'], - ], {useColumnIndex: true}) - - engine.addRows(0, [1, 1]) - - const index = (engine.columnSearch as ColumnIndex) - expectArrayWithSameContent([0], index.getValueIndex(0, 0, 1).index) - expectArrayWithSameContent([2], index.getValueIndex(0, 0, 2).index) - }) -}) - -describe('Adding row - arrays', () => { - it('should be possible to add row above array', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C1:D3'], - [], - [], - ['foo'] - ], {useArrayArithmetic: true}) - - engine.addRows(0, [0, 1]) - - const expected = HyperFormula.buildFromArray([ - [], - ['=-C2:D4'], - [], - [], - ['foo'] - ], {useArrayArithmetic: true}) - - expectEngineToBeTheSameAs(engine, expected) - }) - - it('adding row across array should not change array', () => { - const engine = HyperFormula.buildFromArray([ - [], [], [], - ['=-A1:B3'], - [], [], - ['foo'] - ], {useArrayArithmetic: true}) - - engine.addRows(0, [4, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [], [], [], - ['=-A1:B3'], - [], [], [], - ['foo'] - ], {useArrayArithmetic: true})) - }) - - it('adding row should expand dependent array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ['=TRANSPOSE(A1:B2)'] - ], {useArrayArithmetic: true}) - - engine.addRows(0, [1, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [], - [3, 4], - ['=TRANSPOSE(A1:B3)'] - ], {useArrayArithmetic: true})) - }) - - it('undo add row with dependent array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ['=TRANSPOSE(A1:B2)'] - ], {useArrayArithmetic: true}) - - engine.addRows(0, [1, 1]) - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ['=TRANSPOSE(A1:B2)'] - ], {useArrayArithmetic: true})) - }) - - it('ArrayFormulaVertex#formula should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - ]) - - engine.addRows(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('A4'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B3'))) - }) - - it('ArrayFormulaVertex#formula should be updated when different sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['3', '4'], - ], - Sheet2: [ - ['=TRANSPOSE(Sheet1!A1:B2)'], - ], - }) - - engine.addRows(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B3'))) - }) - - it('ArrayFormulaVertex#address should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - ]) - - engine.addRows(0, [1, 1]) - - const matrixVertex = engine.addressMapping.getCell(adr('A4')) as ArrayFormulaVertex - expect(matrixVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A4')) - }) -}) diff --git a/test/unit/cruds/adding-sheet.spec.ts b/test/unit/cruds/adding-sheet.spec.ts deleted file mode 100644 index 71de7eff54..0000000000 --- a/test/unit/cruds/adding-sheet.spec.ts +++ /dev/null @@ -1,495 +0,0 @@ -import {AlwaysSparse, ErrorType, HyperFormula, SheetNameAlreadyTakenError} from '../../../src' -import {plPL} from '../../../src/i18n/languages' -import {adr, detailedError} from '../testUtils' - -describe('Adding sheet - checking if its possible', () => { - it('yes', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.isItPossibleToAddSheet('Sheet1')).toBe(true) - expect(engine.isItPossibleToAddSheet('~`!@#$%^&*()_-+_=/|?{}[]\\"')).toBe(true) - }) - - it('no', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [], - Foo: [], - }) - - expect(engine.isItPossibleToAddSheet('Sheet1')).toBe(false) - expect(engine.isItPossibleToAddSheet('Foo')).toBe(false) - }) -}) - -describe('add sheet to engine', () => { - it('should add sheet to empty engine', function() { - const engine = HyperFormula.buildEmpty() - - engine.addSheet() - - expect(engine.sheetMapping.numberOfSheets()).toBe(1) - expect(Array.from(engine.sheetMapping.iterateSheetNames())).toEqual(['Sheet1']) - }) - - it('should add sheet to engine with one sheet', function() { - const engine = HyperFormula.buildFromArray([ - ['foo'], - ]) - - engine.addSheet() - - expect(engine.sheetMapping.numberOfSheets()).toBe(2) - expect(Array.from(engine.sheetMapping.iterateSheetNames())).toEqual(['Sheet1', 'Sheet2']) - }) - - it('should be possible to fetch empty cell from newly added sheet', function() { - const engine = HyperFormula.buildEmpty() - - engine.addSheet() - - expect(engine.getCellValue(adr('A1', 0))).toBeNull() - }) - - it('should add sheet with translated sheet name', function() { - HyperFormula.registerLanguage('plPL', plPL) - const engine = HyperFormula.buildEmpty({language: 'plPL'}) - - engine.addSheet() - - expect(engine.sheetMapping.numberOfSheets()).toBe(1) - expect(Array.from(engine.sheetMapping.iterateSheetNames())).toEqual(['Arkusz1']) - }) - - it('should add sheet with given name', function() { - const engine = HyperFormula.buildEmpty() - - engine.addSheet('foo') - - expect(engine.sheetMapping.numberOfSheets()).toBe(1) - expect(Array.from(engine.sheetMapping.iterateSheetNames())).toEqual(['foo']) - }) - - it('cannot add another sheet with same lowercased name', function() { - const engine = HyperFormula.buildEmpty() - engine.addSheet('foo') - - expect(() => { - engine.addSheet('FOO') - }).toThrowError(/already exists/) - - expect(engine.sheetMapping.numberOfSheets()).toBe(1) - expect(Array.from(engine.sheetMapping.iterateSheetNames())).toEqual(['foo']) - }) - - it('should return given name', function() { - const engine = HyperFormula.buildEmpty() - - const sheetName = engine.addSheet('foo') - - expect(sheetName).toBe('foo') - - }) - - it('should return autogenerated name', function() { - const engine = HyperFormula.buildEmpty() - - const sheetName = engine.addSheet() - - expect(sheetName).toBe('Sheet1') - }) - - it('should throw error when sheet name is already taken', () => { - const engine = HyperFormula.buildEmpty() - engine.addSheet('bar') - - expect(() => { - engine.addSheet('bar') - }).toThrow(new SheetNameAlreadyTakenError('bar')) - }) -}) - -describe('recalculates formulas after adding new sheet (issue #1116)', () => { - it('recalculates single cell reference', () => { - const engine = HyperFormula.buildEmpty() - const table1Name = 'table1' - const table2Name = 'table2' - - engine.addSheet(table1Name) - engine.setCellContents(adr('A1', engine.getSheetId(table1Name)), `='${table2Name}'!A1`) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(table1Name)))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(table2Name) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(table2Name)))).toBeNull() - expect(engine.getCellValue(adr('A1', engine.getSheetId(table1Name)))).toBeNull() - - engine.setCellContents(adr('A1', engine.getSheetId(table2Name)), 10) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(table1Name)))).toBe(10) - }) - - it('recalculates chained dependencies across multiple sheets', () => { - const engine = HyperFormula.buildEmpty() - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - const sheet3Name = 'Sheet3' - - engine.addSheet(sheet1Name) - engine.addSheet(sheet2Name) - engine.setCellContents(adr('A1', engine.getSheetId(sheet1Name)), `='${sheet2Name}'!A1+2`) - engine.setCellContents(adr('A1', engine.getSheetId(sheet2Name)), `='${sheet3Name}'!A1*2`) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(sheet3Name) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet3Name)))).toBeNull() - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toBe(0) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(2) - - engine.setCellContents(adr('A1', engine.getSheetId(sheet3Name)), 42) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toBe(84) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(86) - }) - - it('recalculates nested dependencies within same sheet', () => { - const engine = HyperFormula.buildEmpty() - const sheet1Name = 'Sheet1' - const newSheetName = 'NewSheet' - - engine.addSheet(sheet1Name) - engine.setCellContents(adr('B1', engine.getSheetId(sheet1Name)), `='${newSheetName}'!A1`) - engine.setCellContents(adr('A1', engine.getSheetId(sheet1Name)), '=B1*2') - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(newSheetName) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(newSheetName)))).toBeNull() - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toBeNull() - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(0) - - engine.setCellContents(adr('A1', engine.getSheetId(newSheetName)), 15) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toBe(15) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(30) - }) - - it('recalculates multiple cells from different sheets', () => { - const engine = HyperFormula.buildEmpty() - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - const targetSheetName = 'TargetSheet' - - engine.addSheet(sheet1Name) - engine.addSheet(sheet2Name) - engine.setCellContents(adr('A1', engine.getSheetId(sheet1Name)), `='${targetSheetName}'!A1`) - engine.setCellContents(adr('B1', engine.getSheetId(sheet1Name)), `='${targetSheetName}'!B1`) - engine.setCellContents(adr('A1', engine.getSheetId(sheet2Name)), `='${targetSheetName}'!A1+10`) - engine.setCellContents(adr('B1', engine.getSheetId(sheet2Name)), `='${targetSheetName}'!B1+20`) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet2Name)))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(targetSheetName) - engine.setCellContents(adr('A1', engine.getSheetId(targetSheetName)), 5) - engine.setCellContents(adr('B1', engine.getSheetId(targetSheetName)), 7) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(5) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toBe(7) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toBe(15) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet2Name)))).toBe(27) - }) - - it('recalculates formulas with mixed operations', () => { - const engine = HyperFormula.buildEmpty() - const sheet1Name = 'Sheet1' - const newSheetName = 'NewSheet' - - engine.addSheet(sheet1Name) - engine.setCellContents(adr('A1', engine.getSheetId(sheet1Name)), 100) - engine.setCellContents(adr('B1', engine.getSheetId(sheet1Name)), `='${newSheetName}'!A1 + A1`) - engine.setCellContents(adr('C1', engine.getSheetId(sheet1Name)), `='${newSheetName}'!B1 * 2`) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(newSheetName) - engine.setCellContents(adr('A1', engine.getSheetId(newSheetName)), 50) - engine.setCellContents(adr('B1', engine.getSheetId(newSheetName)), 25) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toBe(150) - expect(engine.getCellValue(adr('C1', engine.getSheetId(sheet1Name)))).toBe(50) - }) - - it('recalculates formulas with range references', () => { - const engine = HyperFormula.buildEmpty() - const sheet1Name = 'Sheet1' - const dataSheetName = 'DataSheet' - - engine.addSheet(sheet1Name) - engine.setCellContents(adr('A1', engine.getSheetId(sheet1Name)), `=SUM('${dataSheetName}'!A1:B5)`) - engine.setCellContents(adr('A2', engine.getSheetId(sheet1Name)), `=MEDIAN('${dataSheetName}'!A1:B5)`) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(dataSheetName) - const dataSheetId = engine.getSheetId(dataSheetName) - engine.setCellContents(adr('A1', dataSheetId), 1) - engine.setCellContents(adr('B1', dataSheetId), 2) - engine.setCellContents(adr('A2', dataSheetId), 3) - engine.setCellContents(adr('B2', dataSheetId), 4) - engine.setCellContents(adr('A3', dataSheetId), 5) - engine.setCellContents(adr('B3', dataSheetId), 6) - engine.setCellContents(adr('A4', dataSheetId), 7) - engine.setCellContents(adr('B4', dataSheetId), 8) - engine.setCellContents(adr('A5', dataSheetId), 9) - engine.setCellContents(adr('B5', dataSheetId), 10) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(55) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toBe(5.5) - }) - - it('recalculates named expressions', () => { - const engine = HyperFormula.buildEmpty() - const sheet1Name = 'Sheet1' - const newSheetName = 'NewSheet' - - engine.addSheet(sheet1Name) - engine.addNamedExpression('MyValue', `='${newSheetName}'!$A$1`) - engine.setCellContents(adr('A1', engine.getSheetId(sheet1Name)), '=MyValue') - engine.setCellContents(adr('A2', engine.getSheetId(sheet1Name)), '=MyValue*2') - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(newSheetName) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBeNull() - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toBe(0) - - engine.setCellContents(adr('A1', engine.getSheetId(newSheetName)), 99) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(99) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toBe(198) - }) - - it('setCellContents adds formula referencing existing sheet after it was added', () => { - const engine = HyperFormula.buildFromSheets({ - 'Main': [[1]], - }) - const mainId = engine.getSheetId('Main')! - - engine.addSheet('NewSheet') - const newSheetId = engine.getSheetId('NewSheet')! - engine.setCellContents(adr('A1', newSheetId), 42) - - engine.setCellContents(adr('B1', mainId), '=NewSheet!A1') - - expect(engine.getCellValue(adr('B1', mainId))).toBe(42) - - engine.setCellContents(adr('C1', mainId), '=FutureSheet!A1') - - expect(engine.getCellValue(adr('C1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('FutureSheet') - engine.setCellContents(adr('A1', engine.getSheetId('FutureSheet')), 99) - - expect(engine.getCellValue(adr('C1', mainId))).toBe(99) - }) - - describe('when using ranges with', () => { - it('function using `runFunction`', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [['=MEDIAN(NewSheet!A1:A1)', '=MEDIAN(NewSheet!A1:A2)', '=MEDIAN(NewSheet!A1:A3)', '=MEDIAN(NewSheet!A1:A4)']], - }) - const sheet1Id = engine.getSheetId('FirstSheet')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('NewSheet') - engine.setSheetContent(engine.getSheetId('NewSheet')!, [[1], [2], [3], [4]]) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(1.5) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(2.5) - }) - - it('function not using `runFunction`', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [['=SUM(NewSheet!A1:A1)', '=SUM(NewSheet!A1:A2)', '=SUM(NewSheet!A1:A3)', '=SUM(NewSheet!A1:A4)']], - }, {useArrayArithmetic: false}) - const sheet1Id = engine.getSheetId('FirstSheet')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('NewSheet') - engine.setSheetContent(engine.getSheetId('NewSheet')!, [[1], [2], [3], [4]]) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(3) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(6) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(10) - }) - - it('function using `runFunction` referencing range indirectly', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [ - ['=MEDIAN(A2)', '=MEDIAN(B2)', '=MEDIAN(C2)', '=MEDIAN(D2)'], - ['=\'NewSheet\'!A1:A1', '=\'NewSheet\'!A1:B2', '=\'NewSheet\'!A1:A3', '=\'NewSheet\'!A1:A4'], - ], - }, {useArrayArithmetic: false}) - const sheet1Id = engine.getSheetId('FirstSheet')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('NewSheet') - engine.setSheetContent(engine.getSheetId('NewSheet')!, [[1], [2], [3], [4]]) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(1.5) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(2.5) - }) - - it('function not using `runFunction` referencing range indirectly', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [ - ['=SUM(A2)', '=SUM(B2)', '=SUM(C2)', '=SUM(D2)'], - ['=\'NewSheet\'!A1:A1', '=\'NewSheet\'!A1:B2', '=\'NewSheet\'!A1:A3', '=\'NewSheet\'!A1:A4'], - ], - }, {useArrayArithmetic: false}) - const sheet1Id = engine.getSheetId('FirstSheet')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('NewSheet') - engine.setSheetContent(engine.getSheetId('NewSheet')!, [[1], [2], [3], [4]]) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(3) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(6) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(10) - }) - - it('function calling a named expression', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [['=\'NewSheet\'!A1:A4']], - }, {useArrayArithmetic: false}, [ - { name: 'ExprA', expression: '=MEDIAN(NewSheet!$A$1:$A$1)' }, - { name: 'ExprB', expression: '=MEDIAN(NewSheet!$A$1:$A$2)' }, - { name: 'ExprC', expression: '=MEDIAN(NewSheet!$A$1:$A$3)' }, - { name: 'ExprD', expression: '=MEDIAN(FirstSheet!$A$1)' }, - ]) - - expect(engine.getNamedExpressionValue('ExprA')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprB')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprC')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprD')).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('NewSheet') - engine.setSheetContent(engine.getSheetId('NewSheet')!, [[1], [2], [3], [4]]) - - expect(engine.getNamedExpressionValue('ExprA')).toBe(1) - expect(engine.getNamedExpressionValue('ExprB')).toBe(1.5) - expect(engine.getNamedExpressionValue('ExprC')).toBe(2) - expect(engine.getNamedExpressionValue('ExprD')).toBe(2.5) - }) - }) - - it('should convert placeholder sheet strategy when adding referenced sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'MainSheet': [['=PlaceholderSheet!A1']], - }, { chooseAddressMappingPolicy: new AlwaysSparse()}) - - const mainId = engine.getSheetId('MainSheet')! - - expect(engine.getCellValue(adr('A1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('PlaceholderSheet') - const placeholderId = engine.getSheetId('PlaceholderSheet')! - - engine.setCellContents(adr('A1', placeholderId), 42) - - expect(engine.getCellValue(adr('A1', mainId))).toBe(42) - }) - - it('should handle adding sheet that resolves references with ranges in placeholder', () => { - const engine = HyperFormula.buildFromSheets({ - Main: [['=SUM(Data!A1:A3)']], - }) - - const mainId = engine.getSheetId('Main')! - - expect(engine.getCellValue(adr('A1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('Data') - const dataId = engine.getSheetId('Data')! - engine.setCellContents(adr('A1', dataId), 1) - engine.setCellContents(adr('A2', dataId), 2) - engine.setCellContents(adr('A3', dataId), 3) - - expect(engine.getCellValue(adr('A1', mainId))).toBe(6) - }) - - it('should handle remove and add sheet cycle with range references', () => { - const engine = HyperFormula.buildFromSheets({ - Main: [['=SUM(Data!A1:A3)']], - Data: [[1], [2], [3]], - }) - - const mainId = engine.getSheetId('Main')! - const dataId = engine.getSheetId('Data')! - - expect(engine.getCellValue(adr('A1', mainId))).toBe(6) - - engine.removeSheet(dataId) - - expect(engine.getCellValue(adr('A1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('Data') - const newDataId = engine.getSheetId('Data')! - engine.setCellContents(adr('A1', newDataId), 10) - engine.setCellContents(adr('A2', newDataId), 20) - engine.setCellContents(adr('A3', newDataId), 30) - - expect(engine.getCellValue(adr('A1', mainId))).toBe(60) - }) - - it('should correctly merge sheets when adding sheet that was previously referenced', () => { - const engine = HyperFormula.buildFromSheets({ - Main: [['=NewSheet!A1 + NewSheet!B1']], - }) - - const mainId = engine.getSheetId('Main')! - - expect(engine.getCellValue(adr('A1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('NewSheet') - const newSheetId = engine.getSheetId('NewSheet')! - engine.setCellContents(adr('A1', newSheetId), 100) - engine.setCellContents(adr('B1', newSheetId), 50) - - expect(engine.getCellValue(adr('A1', mainId))).toBe(150) - }) -}) diff --git a/test/unit/cruds/batch-operations.spec.ts b/test/unit/cruds/batch-operations.spec.ts deleted file mode 100644 index f4735a5e0f..0000000000 --- a/test/unit/cruds/batch-operations.spec.ts +++ /dev/null @@ -1,139 +0,0 @@ -import {HyperFormula} from '../../../src' -import {normalizeAddedIndexes, normalizeRemovedIndexes} from '../../../src/Operations' -import {adr, expectArrayWithSameContent} from '../testUtils' - -describe('batch cruds', () => { - it('should run batch cruds and call recompute only once', () => { - const engine = HyperFormula.buildFromArray([ - // - ['foo'], - // - ['bar'], - ]) - - const evaluatorSpy = spyOn(engine.evaluator, 'partialRun') - - engine.batch(() => { - engine.setCellContents(adr('B1'), [['=A1']]) - engine.addRows(0, [0, 1], [1, 1]) - engine.removeRows(0, [0, 1]) - }) - - expect(evaluatorSpy).toHaveBeenCalledTimes(1) - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('A2'))).toBe(null) - expect(engine.getCellValue(adr('A3'))).toEqual('bar') - }) - - it('should run batch cruds unitl fail and call recompute only once', () => { - const engine = HyperFormula.buildFromArray([ - // - ['foo'], - // - ['bar'], - ]) - - const evaluatorSpy = spyOn(engine.evaluator, 'partialRun') - - try { - engine.batch(() => { - engine.setCellContents(adr('B1'), [['=A1']]) - engine.addRows(0, [0, 1], [1, 1]) - engine.removeRows(0, [0, 1]) - engine.addRows(1, [0, 1]) // fail - engine.addRows(0, [0, 1]) - }) - } catch (e) { - // empty line - } - - expect(evaluatorSpy).toHaveBeenCalledTimes(1) - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('A2'))).toBe(null) - expect(engine.getCellValue(adr('A3'))).toEqual('bar') - }) -}) - -describe('normalize added indexes', () => { - it('should return empty array', () => { - const normalized = normalizeAddedIndexes([]) - expectArrayWithSameContent(normalized, []) - }) - - it('should return unchanged one element array', () => { - const normalized = normalizeAddedIndexes([[3, 8]]) - expectArrayWithSameContent(normalized, [[3, 8]]) - }) - - it('should return shifted further indexes when expanding', () => { - const normalized = normalizeAddedIndexes([[3, 3], [7, 3]]) - expectArrayWithSameContent(normalized, [[3, 3], [10, 3]]) - }) - - it('should merge indexes with same start', () => { - const normalized = normalizeAddedIndexes([[3, 3], [3, 7]]) - expectArrayWithSameContent(normalized, [[3, 7]]) - }) - - it('should return shift further indexes - more arguments', () => { - const normalized = normalizeAddedIndexes([[3, 3], [7, 3], [11, 2]]) - expectArrayWithSameContent(normalized, [[3, 3], [10, 3], [17, 2]]) - }) - - it('should return shift further indexes even when they overlap', () => { - const normalized = normalizeAddedIndexes([[3, 5], [8, 5]]) - expectArrayWithSameContent(normalized, [[3, 5], [13, 5]]) - }) - - it('should normalize unsorted indexes', () => { - const normalized = normalizeAddedIndexes([[5, 9], [3, 5]]) - expectArrayWithSameContent(normalized, [[3, 5], [10, 9]]) - }) - - it('mixed case', () => { - const normalized = normalizeAddedIndexes([[3, 7], [3, 2], [2, 1], [15, 15]]) - expectArrayWithSameContent(normalized, [[2, 1], [4, 7], [23, 15]]) - }) -}) - -describe('normalize removed indexes', () => { - it('should return empty array', () => { - const normalized = normalizeRemovedIndexes([]) - expectArrayWithSameContent(normalized, []) - }) - - it('should return unchanged one element array', () => { - const normalized = normalizeRemovedIndexes([[3, 8]]) - expectArrayWithSameContent(normalized, [[3, 8]]) - }) - - it('should return shifted further indexes', () => { - const normalized = normalizeRemovedIndexes([[3, 3], [7, 3]]) - expectArrayWithSameContent(normalized, [[3, 3], [4, 3]]) - }) - - it('should return shift further indexes - more arguments', () => { - const normalized = normalizeRemovedIndexes([[3, 3], [7, 3], [11, 2]]) - expectArrayWithSameContent(normalized, [[3, 3], [4, 3], [5, 2]]) - }) - - it('should normalize adjacent indexes', () => { - const normalized = normalizeRemovedIndexes([[3, 5], [8, 5]]) - expectArrayWithSameContent(normalized, [[3, 10]]) - }) - - it('should normalize overlapping indexes', () => { - const normalized = normalizeRemovedIndexes([[3, 5], [5, 9]]) - expectArrayWithSameContent(normalized, [[3, 11]]) - }) - - it('should normalize unsorted indexes', () => { - const normalized = normalizeRemovedIndexes([[5, 9], [3, 5]]) - expectArrayWithSameContent(normalized, [[3, 11]]) - }) - - it('mixed case', () => { - const normalized = normalizeRemovedIndexes([[3, 7], [4, 8], [1, 1], [15, 5]]) - expectArrayWithSameContent(normalized, [[1, 1], [2, 9], [5, 5]]) - }) -}) diff --git a/test/unit/cruds/change-cell-content.spec.ts b/test/unit/cruds/change-cell-content.spec.ts deleted file mode 100644 index cc083a0d8c..0000000000 --- a/test/unit/cruds/change-cell-content.spec.ts +++ /dev/null @@ -1,1253 +0,0 @@ -import { - CellValueDetailedType, - ErrorType, - ExportedCellChange, - HyperFormula, - InvalidAddressError, - NoSheetWithIdError, - SimpleCellAddress, - SheetSizeLimitExceededError, - ArraySize, - ExpectedValueOfTypeError, -} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {simpleCellAddress} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {ArrayFormulaVertex, EmptyCellVertex, ValueCellVertex} from '../../../src/DependencyGraph' -import {ErrorMessage} from '../../../src/error-message' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import { - adr, - colEnd, - colStart, - detailedError, - expectArrayWithSameContent, - expectEngineToBeTheSameAs, - expectVerticesOfTypes, - noSpace, - rowEnd, - rowStart -} from '../testUtils' - -describe('Changing cell content - checking if its possible', () => { - it('address should have valid coordinates', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToSetCellContents(simpleCellAddress(0, -1, 0))).toEqual(false) - }) - - it('address should be in existing sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToSetCellContents(adr('A1', 1))).toEqual(false) - }) - - it('yes if there is an array', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - [], - ['13'], - ]) - - expect(engine.isItPossibleToSetCellContents(adr('A3'))).toBe(true) - expect(engine.isItPossibleToSetCellContents(AbsoluteCellRange.spanFrom(adr('A3'), 1, 1))).toBe(true) - expect(engine.isItPossibleToSetCellContents(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2))).toBe(true) - expect(engine.isItPossibleToSetCellContents(AbsoluteCellRange.spanFrom(adr('A2'), 2, 2))).toBe(true) - }) - - it('no if content exceeds sheet size limits', () => { - const engine = HyperFormula.buildFromArray([]) - const cellInLastColumn = simpleCellAddress(0, Config.defaultConfig.maxColumns - 1, 0) - const cellInLastRow = simpleCellAddress(0, 0, Config.defaultConfig.maxRows - 1) - expect(engine.isItPossibleToSetCellContents(AbsoluteCellRange.spanFrom(cellInLastColumn, 1, 1))).toEqual(true) - expect(engine.isItPossibleToSetCellContents(AbsoluteCellRange.spanFrom(cellInLastColumn, 2, 1))).toEqual(false) - expect(engine.isItPossibleToSetCellContents(AbsoluteCellRange.spanFrom(cellInLastRow, 1, 1))).toEqual(true) - expect(engine.isItPossibleToSetCellContents(AbsoluteCellRange.spanFrom(cellInLastRow, 1, 2))).toEqual(false) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToSetCellContents(adr('A1'))).toEqual(true) - }) - - it('should throw error if testing with a malformed address', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - engine.isItPossibleToSetCellContents({} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress | SimpleCellRange', 'address')) - }) -}) - -describe('changing cell content', () => { - it('update formula vertex', () => { - const sheet = [ - ['1', '2', '=A1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - let c1 = engine.addressMapping.getCell(adr('C1')) - - expect(engine.graph.existsEdge(a1!, c1!)).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(1) - - engine.setCellContents(adr('C1'), [['=B1']]) - - c1 = engine.addressMapping.getCell(adr('C1')) - expect(engine.graph.existsEdge(a1!, c1!)).toBe(false) - expect(engine.graph.existsEdge(b1!, c1!)).toBe(true) - - expect(engine.getCellValue(adr('C1'))).toBe(2) - }) - - it('update formula to number cell vertex', () => { - const sheet = [ - ['1', '=A1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(1) - engine.setCellContents(adr('B1'), [['7']]) - expect(engine.getCellValue(adr('B1'))).toBe(7) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(false) - }) - - it('update formula to plain text cell vertex', () => { - const sheet = [ - ['1', '=A1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(1) - engine.setCellContents(adr('B1'), [['foo']]) - expect(engine.getCellValue(adr('B1'))).toBe('foo') - expect(engine.graph.existsEdge(a1!, b1!)).toBe(false) - }) - - it('set vertex with edge to empty cell', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ]) - - engine.setCellContents(adr('A1'), [[null]]) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const a2 = engine.addressMapping.getCell(adr('B1')) - expect(a1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a1!, a2!)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toBe(null) - }) - - it('update formula to empty cell', () => { - const sheet = [ - ['1', '=A1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - const a1 = engine.addressMapping.getCellOrThrow(adr('A1')) - const b1 = engine.addressMapping.getCellOrThrow(adr('B1')) - - expect(engine.graph.existsEdge(a1, b1)).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(1) - engine.setCellContents(adr('B1'), [[null]]) - expect(engine.getCellValue(adr('B1'))).toBe(null) - expect([ ...engine.graph.getNodes() ]).not.toContain(b1) - expect(engine.graph.existsEdge(a1, b1)).toBe(false) - }) - - it('update value cell to formula', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - const a1 = engine.addressMapping.getCell(adr('A1')) - let b1 = engine.addressMapping.getCell(adr('B1')) - - expect(engine.graph.existsEdge(a1!, b1!)).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(2) - engine.setCellContents(adr('B1'), [['=A1']]) - - b1 = engine.addressMapping.getCell(adr('B1')) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('update value cell to value cell', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - expect(engine.getCellValue(adr('B1'))).toBe(2) - engine.setCellContents(adr('B1'), [['3']]) - expect(engine.getCellValue(adr('B1'))).toBe(3) - }) - - it('update value cell to value cell with the same value', () => { - const sheet = [ - ['1', '2', '=SUM(A1:B1)'], - ] - const engine = HyperFormula.buildFromArray(sheet) - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - - engine.setCellContents(adr('B1'), [['2']]) - - expect(c1setCellValueSpy).not.toHaveBeenCalled() - }) - - it('update value cell to empty', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - expect(engine.getCellValue(adr('B1'))).toBe(2) - engine.setCellContents(adr('B1'), null) - expect(engine.addressMapping.getCell(adr('B1'))).toBe(undefined) - expect(engine.getCellValue(adr('B1'))).toBe(null) - }) - - it('update value cell to error literal', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - - engine.setCellContents(adr('A1'), '#DIV/0!') - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('update value cell to error-like literal', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - - engine.setCellContents(adr('A1'), '#FOO!') - - expect(engine.getCellValue(adr('A1'))).toEqual('#FOO!') - }) - - it('update value cell to invalid formula', () => { - const engine = HyperFormula.buildFromArray([[1]]) - - engine.setCellContents(adr('A1'), '=SUM(') - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellFormula(adr('A1'))).toEqual('=SUM(') - }) - - it('changing value inside range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '0'], - ['2', '0'], - ['3', '=SUM(A1:A3)'], - ]) - expect(engine.getCellValue(adr('B3'))).toEqual(6) - - engine.setCellContents({sheet: 0, col: 0, row: 0}, '3') - expect(engine.getCellValue(adr('B3'))).toEqual(8) - }) - - it('changing value inside column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '0'], - ['2', '0'], - ['3', '0', '=SUM(A:B)'], - ]) - expect(engine.getCellValue(adr('C3'))).toEqual(6) - - engine.setCellContents({sheet: 0, col: 1, row: 0}, '3') - expect(engine.getCellValue(adr('C3'))).toEqual(9) - }) - - it('changing value inside row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '0'], - ['2', '0'], - ['=SUM(1:2)'], - ]) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - - engine.setCellContents({sheet: 0, col: 1, row: 0}, '3') - expect(engine.getCellValue(adr('A3'))).toEqual(6) - }) - - it('set formula for the first time', () => { - const sheet = [ - ['42', ''], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('B1'), '=A1') - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(42) - }) - - it('set nothing again (2)', () => { - const sheet = [ - [null], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), null) - const a1 = engine.addressMapping.getCell(adr('A1')) - expect(a1).toBe(undefined) - expect(engine.getCellValue(adr('A1'))).toBe(null) - }) - - it('set number for the first time', () => { - const sheet = [ - [null], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), '7') - - expect(engine.getCellValue(adr('A1'))).toBe(7) - }) - - it('set text for the first time', () => { - const sheet = [ - [null], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), 'foo') - - expect(engine.getCellValue(adr('A1'))).toBe('foo') - }) - - it('change empty to formula', () => { - const sheet = [ - ['42', null, '=B1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('B1'), '=A1') - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const c1 = engine.addressMapping.getCell(adr('C1')) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.graph.existsEdge(b1!, c1!)).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(42) - expect(engine.getCellValue(adr('C1'))).toBe(42) - }) - - it('set nothing again', () => { - const sheet = [ - [null, '=A1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), null) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(a1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - }) - - it('change EMPTY to NUMBER', () => { - const sheet = [ - [null, '=A1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), '7') - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toBe(7) - }) - - it('change EMPTY to TEXT', () => { - const sheet = [ - [null, '=A1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), 'foo') - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toBe('foo') - }) - - it('ensure that only part of the tree is evaluated', () => { - const sheet = [ - ['1', '2'], - ['=A1', '=B1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - const a2 = engine.addressMapping.getCell(adr('A2')) - const b2 = engine.addressMapping.getCell(adr('B2')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const a2setCellValueSpy = spyOn(a2 as any, 'setCellValue') - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const b2setCellValueSpy = spyOn(b2 as any, 'setCellValue') - - engine.setCellContents(adr('A1'), '3') - expect(a2setCellValueSpy).toHaveBeenCalled() - expect(b2setCellValueSpy).not.toHaveBeenCalled() - }) - - it('is not possible to set cell content in sheet which does not exist', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - expect(() => { - engine.setCellContents(adr('B1', 1), '3') - }).toThrow(new NoSheetWithIdError(1)) - }) - - it('is not possible to set cell content with invalid address', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - const address = {row: -1, col: 0, sheet: 0} - expect(() => { - engine.setCellContents(address, '3') - }).toThrow(new InvalidAddressError(address)) - }) - - it('remembers if the new formula is structure dependent', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=TRUE()'], - ['1'], - ]) - - engine.setCellContents(adr('C1'), '=COLUMNS(A1:B1)') - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - engine.removeRows(0, [1, 1]) - - expect(c1setCellValueSpy).toHaveBeenCalled() - }) - - it('returns cell value change', () => { - const sheet = [ - ['1'], - ] - - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), '2') - - expect(changes.length).toBe(1) - expect(changes).toContainEqual(new ExportedCellChange(adr('A1'), 2)) - }) - - it('returns dependent formula value change', () => { - const sheet = [ - ['1', '=A1'], - ] - - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), '2') - - expect(changes.length).toBe(2) - expect(changes[0]).toMatchObject(new ExportedCellChange(adr('A1'), 2)) - expect(changes[1]).toMatchObject(new ExportedCellChange(adr('B1'), 2)) - }) - - it('returns dependent matrix value changes', () => { - const sheet = [ - ['1', '2'], - ['3', '4'], - ['=MMULT(A1:B2,A1:B2)'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), '2') - - expect(changes.length).toBe(5) - expectArrayWithSameContent(changes.map((change) => change.newValue), [2, 10, 12, 18, 22]) - }) - - it('update empty cell to parsing error', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.setCellContents(adr('A1'), '=SUM(') - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('update dependency value cell to parsing error', () => { - const sheet = [ - ['1', '=SUM(A1)'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), '=SUM(') - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('update formula cell to parsing error', () => { - const sheet = [ - ['1', '=SUM(A1)'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('B1'), '=SUM(') - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(engine.graph.existsEdge(a1!, b1!)).toBe(false) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('update parsing error to formula', () => { - const sheet = [ - ['1', '=SUM('], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('B1'), '=SUM(A1)') - - expect(engine.getCellValue(adr('B1'))).toEqual(1) - }) - - it('update empty cell to unparsable matrix formula', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.setCellContents(adr('A1'), '=TRANSPOSE(') - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellFormula(adr('A1'))).toEqual('=TRANSPOSE(') - }) - - it('should throw when trying to set cell content outside sheet limits', () => { - const engine = HyperFormula.buildFromArray([]) - const cellInLastColumn = simpleCellAddress(0, Config.defaultConfig.maxColumns, 0) - const cellInLastRow = simpleCellAddress(0, 0, Config.defaultConfig.maxRows) - - expect(() => engine.setCellContents(cellInLastColumn, '1')).toThrow(new SheetSizeLimitExceededError()) - expect(() => engine.setCellContents(cellInLastRow, '1')).toThrow(new SheetSizeLimitExceededError()) - }) - - it('setting empty cells outside sheet limits does not produce error', () => { - const engine = HyperFormula.buildFromArray([]) - const cellInLastColumn = simpleCellAddress(0, Config.defaultConfig.maxColumns, 0) - const cellInLastRow = simpleCellAddress(0, 0, Config.defaultConfig.maxRows) - - expect(() => engine.setCellContents(cellInLastColumn, null)).not.toThrow() - expect(() => engine.setCellContents(cellInLastRow, null)).not.toThrow() - }) - - it('should set matrix with range out of current sheet scope', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.setCellContents(adr('C1'), '=MMULT(A1:B2,A1:B2)') - }) - - it('should set the cell value type based on the format of the input value', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.setCellContents({ sheet: 0, col: 0, row: 0 }, '42') - engine.setCellContents({ sheet: 0, col: 0, row: 1 }, '$42') - engine.setCellContents({ sheet: 0, col: 0, row: 2 }, '42%') - - expect(engine.getCellValueDetailedType({ sheet: 0, col: 0, row: 0 })).toEqual(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType({ sheet: 0, col: 0, row: 1 })).toEqual(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType({ sheet: 0, col: 0, row: 2 })).toEqual(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('should work in scenario from issue https://github.com/handsontable/hyperformula/issues/1297', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, '=SUM(A1:B1)'], - ['=SUM(1:1)', 0, 0], - ['=SUM(1:2)', 0, 0], - ]) - - engine.setCellContents(adr('C1'), [['=SUM(A1:B1)']]) - engine.setCellContents(adr('A3'), [['=SUM(A1:C2)']]) - engine.setCellContents(adr('B1'), [[null]]) - - expect(engine.getCellValue(adr('A3'))).toEqual(4) - }) -}) - -describe('change multiple cells contents', () => { - it('works for one', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('B1'), [['3']]) - expect(engine.getCellValue(adr('B1'))).toBe(3) - }) - - it('works for many', () => { - const sheet = [ - ['1', '2', '3'], - ['4', '5', '6'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('B1'), [ - ['12', '13'], - ['15', '16'], - ['18', '19'], - ]) - expect(engine.getCellValue(adr('B1'))).toBe(12) - expect(engine.getCellValue(adr('C1'))).toBe(13) - expect(engine.getCellValue(adr('B2'))).toBe(15) - expect(engine.getCellValue(adr('C2'))).toBe(16) - expect(engine.getCellValue(adr('B3'))).toBe(18) - expect(engine.getCellValue(adr('C3'))).toBe(19) - }) - - it('recompute only once', () => { - const sheet = [ - ['1', '2', '3'], - ['4', '5', '6'], - ] - const engine = HyperFormula.buildFromArray(sheet) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const evaluatorCallSpy = spyOn(engine.evaluator as any, 'partialRun') - - engine.setCellContents(adr('B1'), [ - ['12', '13'], - ['15', '16'], - ['18', '19'], - ]) - - expect(evaluatorCallSpy).toHaveBeenCalledTimes(1) - }) - - it('possible to change matrices', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.setCellContents(adr('A1'), [['42', '18', '=MMULT(A1:B1,TRANSPOSE(A1:B1))']]) - expect(engine.getCellValue(adr('A1'))).toBe(42) - expect(engine.getCellValue(adr('B1'))).toBe(18) - expect(engine.getCellValue(adr('C1'))).toBe(2088) - }) - - it('returns changes of multiple values', () => { - const sheet = [ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), [['7', '8'], ['9', '10']]) - - expect(changes.length).toEqual(4) - expectArrayWithSameContent(changes.map((change) => change.newValue), [7, 8, 9, 10]) - }) - - it('returns changes of multiple values dependent formulas', () => { - const sheet = [ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(A1:B1)', '=SUM(B1:B2)'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), [['7', '8'], ['9', '10']]) - - expect(changes.length).toEqual(6) - expectArrayWithSameContent(changes.map((change) => change.newValue), [7, 8, 9, 10, 15, 18]) - }) - - it('should throw when trying to set cell contents outside sheet limits', () => { - const engine = HyperFormula.buildFromArray([]) - const cellInLastColumn = simpleCellAddress(0, Config.defaultConfig.maxColumns - 1, 0) - const cellInLastRow = simpleCellAddress(0, 0, Config.defaultConfig.maxRows - 1) - - expect(() => engine.setCellContents(cellInLastColumn, [['1', '2']])).toThrow(new SheetSizeLimitExceededError()) - expect(() => engine.setCellContents(cellInLastRow, [['1'], ['2']])).toThrow(new SheetSizeLimitExceededError()) - }) -}) - -describe('updating column index', () => { - it('should update column index when changing simple value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '15'], - ], {useColumnIndex: true}) - - engine.setCellContents(adr('B2'), '8') - - expectArrayWithSameContent((engine.columnSearch as ColumnIndex).getValueIndex(0, 1, 15).index, []) - expectArrayWithSameContent((engine.columnSearch as ColumnIndex).getValueIndex(0, 1, 8).index, [1]) - }) - - it('should update column index when clearing cell content', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ], {useColumnIndex: true}) - - engine.setCellContents(adr('B1'), null) - - expectArrayWithSameContent((engine.columnSearch as ColumnIndex).getValueIndex(0, 1, 2).index, []) - }) - - it('should update column index when changing to ParsingError', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ], {useColumnIndex: true}) - - engine.setCellContents(adr('B1'), '=SUM(') - - expectArrayWithSameContent((engine.columnSearch as ColumnIndex).getValueIndex(0, 1, 2).index, []) - }) - - it('should update column index when changing to formula', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ], {useColumnIndex: true}) - - engine.setCellContents(adr('B1'), '=SUM(A1)') - - expectArrayWithSameContent((engine.columnSearch as ColumnIndex).getValueIndex(0, 1, 2).index, []) - expectArrayWithSameContent((engine.columnSearch as ColumnIndex).getValueIndex(0, 1, 1).index, [0]) - }) -}) - -describe('column ranges', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A:B)'] - ]) - - engine.setCellContents(adr('A1'), '3') - - expect(engine.getCellValue(adr('C1'))).toEqual(5) - }) - - it('works when new content is added beyond previous sheet size', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A:B)'] - ]) - - engine.setCellContents(adr('A2'), '3') - - const range = engine.rangeMapping.getVertexOrThrow(colStart('A'), colEnd('B')) - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(engine.graph.existsEdge(a2!, range)).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(6) - }) - - it('works when adding matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B:C)'], - ['1'], - ['2'], - ]) - - engine.setCellContents(adr('B1'), '=TRANSPOSE(A2:A3)') - - const range = engine.rangeMapping.getVertexOrThrow(colStart('B'), colEnd('C')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const c1 = engine.addressMapping.getCell(adr('C1')) - expect(engine.graph.existsEdge(b1!, range)).toEqual(true) - expect(engine.graph.existsEdge(c1!, range)).toEqual(true) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) -}) - -describe('row ranges', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=SUM(1:2)'] - ]) - - engine.setCellContents(adr('A1'), '3') - - expect(engine.getCellValue(adr('A3'))).toEqual(5) - }) - - it('works when new content is added beyond previous sheet size', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=SUM(1:2)'] - ]) - - engine.setCellContents(adr('B1'), '3') - - const range = engine.rangeMapping.getVertexOrThrow(rowStart(1), rowEnd(2)) - const b1 = engine.addressMapping.getCell(adr('B1')) - expect(engine.graph.existsEdge(b1!, range)).toEqual(true) - expect(engine.getCellValue(adr('A3'))).toEqual(6) - }) - - it('works when adding matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2:3)', '1', '2'], - ]) - - engine.setCellContents(adr('A2'), '=TRANSPOSE(B1:C1)') - - const range = engine.rangeMapping.getVertexOrThrow(rowStart(2), rowEnd(3)) - const a2 = engine.addressMapping.getCell(adr('A2')) - const a3 = engine.addressMapping.getCell(adr('A3')) - expect(engine.graph.existsEdge(a2!, range)).toEqual(true) - expect(engine.graph.existsEdge(a3!, range)).toEqual(true) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) -}) - -describe('arrays', () => { - it('should set array to cell', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('C1'), [['=-A1:B2']]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2, '=-A1:B2'], - [3, 4], - ], {useArrayArithmetic: true})) - }) - - it('should be REF array if no space for result', () => { - const engine = HyperFormula.buildFromArray([ - [], - [1], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('A1'), [['=-B2:B3']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(noSpace()) - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['=-B2:B3'], - [1], - ], {useArrayArithmetic: true})) - }) - - it('should be REF array if no space and potential cycle', () => { - const engine = HyperFormula.buildFromArray([ - [], - [1], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('A1'), [['=-A2:A3']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(noSpace()) - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['=-A2:A3'], - [1], - ], {useArrayArithmetic: true})) - }) - - it('should shrink to one vertex if there is more content colliding with array', () => { - const engine = HyperFormula.buildFromArray([], {useArrayArithmetic: true}) - - engine.setCellContents(adr('A1'), [ - ['=-C1:D2'], - [1] - ]) - - expect(engine.arrayMapping.getArrayByCorner(adr('A1'))?.array.size).toEqual(ArraySize.error()) - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, undefined], - [ValueCellVertex, undefined], - ]) - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['=-C1:D2', null], - [1, null] - ], {useArrayArithmetic: true})) - }) - - it('should be separate arrays', () => { - const engine = HyperFormula.buildFromArray([], {useArrayArithmetic: true}) - - engine.setCellContents(adr('A1'), [ - ['=TRANSPOSE(D1:E2)', '=TRANSPOSE(D1:E2)'], - ['=TRANSPOSE(D1:E2)', '=TRANSPOSE(D1:E2)'], - ]) - - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, ArrayFormulaVertex, undefined], - [ArrayFormulaVertex, ArrayFormulaVertex, ArrayFormulaVertex], - [undefined, ArrayFormulaVertex, ArrayFormulaVertex], - ]) - expect(engine.arrayMapping.arrayMapping.size).toEqual(4) - }) - - it('should REF last array', () => { - const engine = HyperFormula.buildFromArray([ - [null, null, null, 1, 2], - [null, null, null, 1, 2], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('A1'), [ - ['=TRANSPOSE(D1:E2)', '=TRANSPOSE(D1:E2)'], - ['=TRANSPOSE(D1:E2)'], - ]) - - expectVerticesOfTypes(engine, [ - [ArrayFormulaVertex, ArrayFormulaVertex, ArrayFormulaVertex], - [ArrayFormulaVertex, ArrayFormulaVertex, ArrayFormulaVertex], - [undefined, undefined], - ]) - expect(engine.getSheetValues(0)).toEqual([ - [noSpace(), 1, 1, 1, 2], - [noSpace(), 2, 2, 1, 2], - ]) - expect(engine.arrayMapping.arrayMapping.size).toEqual(3) - }) - - it('should make existing array REF and change cell content to simple value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '=B4'], - ['=-A1:B2'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('B4'), [['foo']]) - - expect(engine.getSheetValues(0)).toEqual([ - [1, 2], - [3, 4, 'foo'], - [noSpace()], - [null, 'foo'] - ]) - }) - - it('should not change cell to empty if part of an array', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '=B4'], - ['=-A1:B2'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('B4'), [[null]]) - - expect(engine.getSheetValues(0)).toEqual([ - [1, 2], - [3, 4, -4], - [-1, -2], - [-3, -4], - ]) - }) - - it('should make existing array REF and change cell content to formula', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '=B4'], - ['=-A1:B2'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('B4'), [['=SUM(A1:B2)']]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4, '=B4'], - ['=-A1:B2'], - [undefined, '=SUM(A1:B2)'] - ], {useArrayArithmetic: true})) - expect(engine.getSheetValues(0)).toEqual([ - [1, 2], - [3, 4, 10], - [noSpace()], - [null, 10] - ]) - }) - - it('should make existing array REF and change cell content to parsing error', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '=B4'], - ['=-A1:B2'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('B4'), [['=SUM(']]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4, '=B4'], - ['=-A1:B2'], - [null, '=SUM('] - ], {useArrayArithmetic: true})) - }) - - it('should make existing matrix REF and set new array', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '=B4'], - ['=-A1:B2'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('B3'), [['=+A1:B2']]) - - expect(engine.getSheetValues(0)).toEqual([ - [1, 2], - [3, 4, 3], - [noSpace(), 1, 2], - [null, 3, 4] - ]) - }) - - it('should replace one array with another', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=-A1:B2'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('A3'), [['=2*A1:B2']]) - - expect(engine.getSheetValues(0)).toEqual([ - [1, 2], - [3, 4], - [2, 4], - [6, 8], - ]) - }) - - it('should adjust dependent formulas after shrinking array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C1', null, null, 4], - ['=D1', '=E1', '=SUM(E1, F1:G1)'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('E1'), [['foo']]) - engine.setCellContents(adr('D1'), [[4, 5, 6]]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2, 3, 4, 5, 6, 4], - ['=D1', '=E1', '=SUM(E1, F1:G1)'] - ], {useArrayArithmetic: true})) - }) - - it('should adjust dependent ranges after shrinking array taking smaller vertices into account', () => { - const engine = HyperFormula.buildFromArray([ - [1, '=-A1:A3', '=SUM(B1:B2)', '=SUM(B1:B3)'], - [2], - [3], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('B1'), 'foo') - engine.setCellContents(adr('B1'), [[4], [5], [6]]) - - const b1 = engine.dependencyGraph.getCell(adr('b1'))! - const b2 = engine.dependencyGraph.getCell(adr('b2'))! - const b3 = engine.dependencyGraph.getCell(adr('b3'))! - const b1b2 = engine.rangeMapping.getRangeVertex(adr('b1'), adr('b2'))! - const b1b3 = engine.rangeMapping.getRangeVertex(adr('b1'), adr('b3'))! - - expect(engine.graph.existsEdge(b1, b1b2)).toBe(true) - expect(engine.graph.existsEdge(b2, b1b2)).toBe(true) - expect(engine.graph.existsEdge(b1b2, b1b3)).toBe(true) - expect(engine.graph.existsEdge(b1, b1b3)).toBe(false) - expect(engine.graph.existsEdge(b2, b1b3)).toBe(false) - expect(engine.graph.existsEdge(b3, b1b3)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 4, '=SUM(B1:B2)', '=SUM(B1:B3)'], - [2, 5], - [3, 6], - ], {useArrayArithmetic: true})) - }) - - it('should return values of a range in changes', () => { - const engine = HyperFormula.buildFromArray([[1, 2]], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('A2'), [['=-A1:B1']]) - - expect(changes.length).toEqual(2) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), -1)) - expect(changes).toContainEqual(new ExportedCellChange(adr('B2'), -2)) - }) - - it('should return changed content when replacing array left corner', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=-A1:B1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('A2'), [['foo']]) - - expect(changes.length).toEqual(2) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), 'foo')) - expect(changes).toContainEqual(new ExportedCellChange(adr('B2'), null)) - }) - - it('should return changed content when replacing any array cell with simple value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['=-A1:C1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('B2'), [['foo']]) - - expect(changes.length).toEqual(3) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), noSpace())) - expect(changes).toContainEqual(new ExportedCellChange(adr('B2'), 'foo')) - expect(changes).toContainEqual(new ExportedCellChange(adr('C2'), null)) - }) - - it('should return changed content when replacing any array cell with parsing error', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['=-A1:C1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('B2'), [['=SUM(']]) - - expect(changes.length).toEqual(3) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), noSpace())) - expect(changes).toContainEqual(new ExportedCellChange(adr('B2'), detailedError(ErrorType.ERROR, "Parsing error. Expecting token of type --> RParen <-- but found --> '' <--"))) - expect(changes).toContainEqual(new ExportedCellChange(adr('C2'), null)) - }) - - it('should return changed content when clearing array left corner', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=-A1:B1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('A2'), null) - - expect(changes.length).toEqual(2) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), null)) - expect(changes).toContainEqual(new ExportedCellChange(adr('B2'), null)) - }) - - it('should return no changes when trying to clear array cell', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=-A1:B1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('B2'), null) - - expect(changes.length).toEqual(0) - }) - - it('should return changed content when replacing array to another smaller one', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['=-A1:C1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('A2'), [['=+A1:B1']]) - - expect(changes.length).toEqual(3) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), 1)) - expect(changes).toContainEqual(new ExportedCellChange(adr('B2'), 2)) - expect(changes).toContainEqual(new ExportedCellChange(adr('C2'), null)) - }) - - it('should return changed content when replacing array to smaller one even if values are same', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['=-A1:C1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('A2'), [['=-A1:B1']]) - - expect(changes.length).toEqual(3) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), -1)) - expect(changes).toContainEqual(new ExportedCellChange(adr('B2'), -2)) - expect(changes).toContainEqual(new ExportedCellChange(adr('C2'), null)) - }) - - it('should return REF in changes', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C1'], - ], {useArrayArithmetic: true}) - - const changes = engine.setCellContents(adr('E1'), [['foo']]) - - expect(changes).toContainEqual(new ExportedCellChange(adr('D1'), noSpace())) - expect(changes).toContainEqual(new ExportedCellChange(adr('E1'), 'foo')) - expect(changes).toContainEqual(new ExportedCellChange(adr('F1'), null)) - }) - - it('should undo REF', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C1', null, null, 4], - ['=D1', '=E1', '=SUM(F1:F1)', '=SUM(F1:G1)'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('E1'), [['foo']]) - engine.setCellContents(adr('D1'), [[4, 5, 6]]) - engine.undo() - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C1', null, null, 4], - ['=D1', '=E1', '=SUM(F1:F1)', '=SUM(F1:G1)'], - ], {useArrayArithmetic: true})) - - expect(engine.getCellValue(adr('A2'))).toEqual(-1) - expect(engine.getCellValue(adr('B2'))).toEqual(-2) - expect(engine.getCellValue(adr('C2'))).toEqual(-3) - expect(engine.getCellValue(adr('D2'))).toEqual(1) - }) - - it('should redo REF', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C1', null, null, 4], - ['=D1', '=E1', '=SUM(F1:F1)', '=SUM(F1:G1)'], - ], {useArrayArithmetic: true}) - - engine.setCellContents(adr('E1'), [['foo']]) - engine.undo() - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C1', 'foo', null, 4], - ['=D1', '=E1', '=SUM(F1:F1)', '=SUM(F1:G1)'], - ], {useArrayArithmetic: true})) - }) - - xit('should recalculate matrix if space is available', () => { - const engine = HyperFormula.buildFromArray([ - ['=+C1:D1', 'foo', 1, 2] - ], {useArrayArithmetic: true}) - expect(engine.getCellValue(adr('A1'))).toEqual(noSpace()) - - engine.setCellContents(adr('B1'), null) - - expect(engine.getSheetValues(0)).toEqual([ - [1, 2, 1, 2] - ]) - }) -}) diff --git a/test/unit/cruds/clear-sheet.spec.ts b/test/unit/cruds/clear-sheet.spec.ts deleted file mode 100644 index 2e69f2eaea..0000000000 --- a/test/unit/cruds/clear-sheet.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -import {HyperFormula, NoSheetWithIdError} from '../../../src' -import {adr} from '../testUtils' - -describe('Clear sheet - checking if its possible', () => { - it('no if theres no such sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToClearSheet(1)).toEqual(false) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToClearSheet(0)).toEqual(true) - }) -}) - -describe('Clear sheet content', () => { - it('should throw error when trying to clear not existing sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(() => { - engine.clearSheet(1) - }).toThrow(new NoSheetWithIdError(1)) - }) - - it('should clear sheet content', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'foo'], - ]) - - engine.clearSheet(0) - - expect(engine.getCellValue(adr('A1'))).toBe(null) - expect(engine.getCellValue(adr('B1'))).toBe(null) - }) - - it('should recalculate and return changes', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], - ], - Sheet2: [ - ['=Sheet1!A1'], - ['=SUM(1, Sheet1!A1)'], - ], - }) - - const changes = engine.clearSheet(0) - - expect(engine.getCellValue(adr('A1', 1))).toBe(null) - expect(engine.getCellValue(adr('A2', 1))).toEqual(1) - - expect(changes.length).toEqual(2) - }) - - it('should clear sheet with matrix', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ], - Sheet2: [ - ['=Sheet1!A2'], - ['=Sheet1!A3'], - ], - }) - - const changes = engine.clearSheet(0) - - expect(engine.getCellValue(adr('A1', 1))).toBe(null) - expect(engine.getCellValue(adr('A2', 1))).toBe(null) - - expect(changes.length).toEqual(2) - }) - - it('should clear sheet and dont break edge between cells', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], - ], - Sheet2: [ - ['=Sheet1!A1'], - ], - }) - - engine.clearSheet(0) - engine.setCellContents(adr('A1'), '2') - - expect(engine.getCellValue(adr('A1', 1))).toEqual(2) - }) - - it('should clear sheet and dont break edge between cells, case with range', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [[ '1' ]], - Sheet2: [[ '=SUM(Sheet1!A1:B1)' ]], - }) - - engine.clearSheet(0) - engine.setCellContents(adr('A1'), '2') - engine.setCellContents(adr('B1'), '3') - - expect(engine.getCellValue(adr('A1', 1))).toEqual(5) - }) -}) diff --git a/test/unit/cruds/copy-paste.spec.ts b/test/unit/cruds/copy-paste.spec.ts deleted file mode 100644 index 44674cd862..0000000000 --- a/test/unit/cruds/copy-paste.spec.ts +++ /dev/null @@ -1,525 +0,0 @@ -import {ExportedCellChange, HyperFormula, NothingToPasteError, SimpleCellAddress} from '../../../src' -import {AbsoluteCellRange, SimpleCellRange} from '../../../src/AbsoluteCellRange' -import {ErrorType, simpleCellAddress} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {SheetSizeLimitExceededError} from '../../../src/errors' -import {CellAddress} from '../../../src/parser' -import { - adr, - colEnd, - colStart, - detailedError, - expectArrayWithSameContent, - extractReference, - rowEnd, - rowStart, -} from '../testUtils' -import { DependencyGraph } from '../../../src/DependencyGraph' -import { Statistics } from '../../../src/statistics' -import { FunctionRegistry } from '../../../src/interpreter/FunctionRegistry' -import { LazilyTransformingAstService } from '../../../src/LazilyTransformingAstService' -import { NamedExpressions } from '../../../src/NamedExpressions' -import { Operations } from '../../../src/Operations' -import { buildColumnSearchStrategy } from '../../../src/Lookup/SearchStrategy' -import { CellContentParser } from '../../../src/CellContentParser' -import { DateTimeHelper } from '../../../src/DateTimeHelper' -import { NumberLiteralHelper } from '../../../src/NumberLiteralHelper' -import { ParserWithCaching } from '../../../src/parser' -import { ArraySizePredictor } from '../../../src/ArraySize' -import { NoSheetWithIdError} from '../../../src' -import {ExpectedValueOfTypeError} from '../../../src/errors' - -describe('Copy - paste integration', () => { - it('copy should validate arguments', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(() => { - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 0, 42)) - }).toThrowError('Invalid arguments, expected width to be positive integer.') - - expect(() => { - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), -1, 42)) - }).toThrowError('Invalid arguments, expected width to be positive integer.') - - expect(() => { - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 3.14, 42)) - }).toThrowError('Invalid arguments, expected width to be positive integer.') - - expect(() => { - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 42, 0)) - }).toThrowError('Invalid arguments, expected height to be positive integer.') - - expect(() => { - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 42, -1)) - }).toThrowError('Invalid arguments, expected height to be positive integer.') - - expect(() => { - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 42, 3.14)) - }).toThrowError('Invalid arguments, expected height to be positive integer.') - - expect(() => { - engine.copy({} as SimpleCellRange) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) - - it('paste raise error when there is nothing in clipboard', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(() => { - engine.paste(adr('A2')) - }).toThrow(new NothingToPasteError()) - }) - - it('copy should return values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['foo', '=A1'], - ]) - - const values = engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - - expectArrayWithSameContent([1, 2], values[0]) - expectArrayWithSameContent(['foo', 1], values[1]) - }) - - it('copy should round return values', () => { - const engine = HyperFormula.buildFromArray([ - ['1.0000000001', '1.000000000000001'], - ]) - - const values = engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - - expectArrayWithSameContent([1.0000000001, 1], values[0]) - }) - - it('should copy empty cell vertex', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=A1'] - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - const changes = engine.paste(adr('A2')) - - expectArrayWithSameContent([new ExportedCellChange(adr('A2'), null)], changes) - }) - - it('should work for single number', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - expect(engine.getCellValue(adr('B1'))).toEqual(1) - }) - - it('should work for parsing error', () => { - const sheet = [ - ['=SUM('], - ] - const engine = HyperFormula.buildFromArray(sheet) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - expect(engine.getCellFormula(adr('B1'))).toEqual('=SUM(') - }) - - it('should work for area', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['foo', 'bar'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('C1')) - - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('D1'))).toEqual(2) - expect(engine.getCellValue(adr('C2'))).toEqual('foo') - expect(engine.getCellValue(adr('D2'))).toEqual('bar') - }) - - it('should not round here', () => { - const engine = HyperFormula.buildFromArray([ - ['1.0000000001', '1.000000000000001'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - engine.paste(adr('A2')) - - expect(engine.dependencyGraph.getCellValue(adr('A2'))).toEqual(1.0000000001) - expect(engine.dependencyGraph.getCellValue(adr('B2'))).toEqual(1.000000000000001) - }) - - it('should work for cell reference inside copied area', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - engine.paste(adr('A2')) - - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - const a2 = engine.dependencyGraph.fetchCell(adr('A2')) - const b2 = engine.dependencyGraph.fetchCell(adr('B2')) - - expect(engine.dependencyGraph.existsEdge(a2, b2)).toBe(true) - expect(engine.dependencyGraph.existsEdge(a1, b2)).toBe(false) - expect(engine.getCellValue(adr('B2'))).toEqual(1) - }) - - it('should work for absolute cell reference', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=$A$1'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.paste(adr('B2')) - - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - const b1 = engine.dependencyGraph.fetchCell(adr('B1')) - const b2 = engine.dependencyGraph.fetchCell(adr('B2')) - - expect(engine.dependencyGraph.existsEdge(a1, b1)).toBe(true) - expect(engine.dependencyGraph.existsEdge(a1, b2)).toBe(true) - expect(engine.getCellValue(adr('B2'))).toEqual(1) - }) - - it('should work for cell reference pointing outside copied area', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ['2', ''], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.paste(adr('B2')) - - expect(engine.getCellValue(adr('B2'))).toEqual(2) - }) - - it('should return ref when pasted reference is out of scope', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - [null, '=A1'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B2'), 1, 1)) - engine.paste(adr('A1')) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellSerialized(adr('A1'))).toEqual('=#REF!') - }) - - it('should return ref when pasted range is out of scope', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - [null, '=A1:B2'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B2'), 1, 1)) - engine.paste(adr('A1')) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellSerialized(adr('A1'))).toEqual('=#REF!') - }) - - it('should return ref when pasted range is out of scope 2', () => { - const engine = HyperFormula.buildFromArray([ - [null, null, null], - [null, null, null], - [null, null, '=SUM(A1:B2)'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('C3'), 1, 1)) - engine.paste(adr('B2')) - - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellSerialized(adr('B2'))).toEqual('=SUM(#REF!)') - }) - - it('should return ref when pasted column range is out of scope', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - [null, '=A:B'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B2'), 1, 1)) - engine.paste(adr('A1')) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellSerialized(adr('A1'))).toEqual('=#REF!') - }) - - it('should return ref when pasted row range is out of scope', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - [null, '=1:2'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B2'), 1, 1)) - engine.paste(adr('A1')) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellSerialized(adr('A1'))).toEqual('=#REF!') - }) - - it('should create new range vertex - cell range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '3'], - ['2', '4'], - ['=SUM(A1:A2)'] - ]) - expect(Array.from(engine.dependencyGraph.rangeMapping.rangesInSheet(0)).length).toBe(1) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A3'), 1, 1)) - engine.paste(adr('B3')) - - expect(engine.getCellValue(adr('B3'))).toEqual(7) - expect(Array.from(engine.dependencyGraph.rangeMapping.rangesInSheet(0)).length).toBe(2) - expect(engine.dependencyGraph.getRange(adr('B1'), adr('B2'))).not.toBeUndefined() - }) - - it('should create new range vertex - column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '3', '5', '=SUM(A:B)'], - ['2', '4', '6', null], - ]) - expect(Array.from(engine.dependencyGraph.rangeMapping.rangesInSheet(0)).length).toBe(1) - - engine.copy(AbsoluteCellRange.spanFrom(adr('D1'), 1, 1)) - engine.paste(adr('E1')) - - expect(engine.getCellValue(adr('E1'))).toEqual(18) - expect(Array.from(engine.dependencyGraph.rangeMapping.rangesInSheet(0)).length).toBe(2) - expect(engine.dependencyGraph.getRange(colStart('B'), colEnd('C'))).not.toBeUndefined() - }) - - it('should create new range vertex - row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(1:2)'] - ]) - expect(Array.from(engine.dependencyGraph.rangeMapping.rangesInSheet(0)).length).toBe(1) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A4'), 1, 1)) - engine.paste(adr('A5')) - - expect(engine.getCellValue(adr('A5'))).toEqual(18) - expect(Array.from(engine.dependencyGraph.rangeMapping.rangesInSheet(0)).length).toBe(2) - expect(engine.dependencyGraph.getRange(rowStart(2), rowEnd(3))).not.toBeUndefined() - }) - - it('should update edges between infinite range and pasted values', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2:3)', '1', '=SUM(1, 2)'] - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.paste(adr('A2')) - engine.copy(AbsoluteCellRange.spanFrom(adr('C1'), 1, 1)) - engine.paste(adr('A3')) - - const range = engine.rangeMapping.getVertexOrThrow(rowStart(2), rowEnd(3)) - const a2 = engine.addressMapping.getCell(adr('A2')) - const a3 = engine.addressMapping.getCell(adr('A3')) - expect(engine.graph.existsEdge(a2!, range)).toBe(true) - expect(engine.graph.existsEdge(a3!, range)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('paste should return newly pasted values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - const changes = engine.paste(adr('A2')) - - expectArrayWithSameContent([ - new ExportedCellChange(adr('A2'), 1), - new ExportedCellChange(adr('B2'), 1), - ], changes) - }) - - it('should copy values from formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - ]) - expect(engine.arrayMapping.arrayMapping.size).toEqual(1) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A3'), 2, 2)) - engine.paste(adr('A5')) - - expect(engine.arrayMapping.arrayMapping.size).toEqual(1) - expect(engine.getCellFormula(adr('A5'))).toBe(undefined) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - expect(engine.getCellValue(adr('B5'))).toEqual(3) - expect(engine.getCellValue(adr('A6'))).toEqual(2) - expect(engine.getCellValue(adr('B6'))).toEqual(4) - }) - - it('should not be possible to paste onto formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - - expect(() => { - engine.paste(adr('A3')) - }).toThrowError('It is not possible to paste onto an array') - }) - - it('should not be possible to paste to not existing sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=Sheet1!A2', '=Sheet2!A2']], - }) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - - expect(() => { - engine.paste(adr('A1', 1)) - }).toThrowError('Invalid arguments, expected a valid target address.') - }) - - it('should copy references with absolute sheet id', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=Sheet1!A2', '=Sheet2!A2']], - 'Sheet2': [] - }) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - engine.paste(adr('A1', 1)) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(0, 1, 0)) - expect(extractReference(engine, adr('B1', 1))).toEqual(CellAddress.relative(-1, 1, 1)) - }) - - it('sheet reference should stay "relative" to other sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=A2']], - 'Sheet2': [] - }) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A1', 1)) - - expect(extractReference(engine, adr('A1', 1))).toEqual(CellAddress.relative(0, 1)) - }) - - it('should throw error when trying to paste beyond sheet size limit', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ]) - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - - expect(() => engine.paste(simpleCellAddress(0, Config.defaultConfig.maxColumns, 0))).toThrow(new SheetSizeLimitExceededError()) - expect(() => engine.paste(simpleCellAddress(0, 0, Config.defaultConfig.maxRows))).toThrow(new SheetSizeLimitExceededError()) - }) - - it('should throw error when trying to paste when targetLeftCorner is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - engine.paste({} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'targetLeftCorner')) - }) -}) - -describe('Copy - paste integration - actions at the Operations layer', () => { - let operations: Operations - - beforeEach(() => { - const config = new Config() - const stats = new Statistics() - const namedExpressions = new NamedExpressions() - const functionRegistry = new FunctionRegistry(config) - const lazilyTransformingAstService = new LazilyTransformingAstService(stats) - const dependencyGraph = DependencyGraph.buildEmpty(lazilyTransformingAstService, config, functionRegistry, namedExpressions, stats) - const columnSearch = buildColumnSearchStrategy(dependencyGraph, config, stats) - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralHelper = new NumberLiteralHelper(config) - const cellContentParser = new CellContentParser(config, dateTimeHelper, numberLiteralHelper) - const parser = new ParserWithCaching( - config, - functionRegistry, - dependencyGraph.sheetReferenceRegistrar.ensureSheetRegistered.bind(dependencyGraph.sheetReferenceRegistrar) - ) - const arraySizePredictor = new ArraySizePredictor(config, functionRegistry) - operations = new Operations(config, dependencyGraph, columnSearch, cellContentParser, parser, stats, lazilyTransformingAstService, namedExpressions, arraySizePredictor) - }) - - it('should throw an error if you try and copy from a sheet that does not exist', () => { - const sheetId = 5 - expect(() => { - operations.getOldContent(simpleCellAddress(sheetId, 0, 0)) - }).toThrow(new NoSheetWithIdError(sheetId)) - }) -}) - -describe('isClipboardEmpty', () => { - it('when just engine initialized', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('after copy', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - - expect(engine.isClipboardEmpty()).toBe(false) - }) - - it('after copy-paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - expect(engine.isClipboardEmpty()).toBe(false) - }) - - it('after cut', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - - expect(engine.isClipboardEmpty()).toBe(false) - }) - - it('after cut-paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('after clearClipboard', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ]) - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - engine.clearClipboard() - - expect(engine.isClipboardEmpty()).toBe(true) - }) -}) diff --git a/test/unit/cruds/cut-paste.spec.ts b/test/unit/cruds/cut-paste.spec.ts deleted file mode 100644 index 37a5e454bb..0000000000 --- a/test/unit/cruds/cut-paste.spec.ts +++ /dev/null @@ -1,1024 +0,0 @@ -import {ErrorType, HyperFormula, NoSheetWithIdError} from '../../../src' -import {AbsoluteCellRange, SimpleCellRange} from '../../../src/AbsoluteCellRange' -import {EmptyCellVertex} from '../../../src/DependencyGraph' -import {EmptyValue} from '../../../src/interpreter/InterpreterValue' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import {CellAddress} from '../../../src/parser' -import { - adr, - detailedError, - expectArrayWithSameContent, - expectEngineToBeTheSameAs, - extractMatrixRange, - extractRange, - extractReference, graphEdgesCount, -} from '../testUtils' -import {ExpectedValueOfTypeError} from '../../../src/errors' - -describe('Address dependencies, moved formulas', () => { - it('should update dependency to external cell when not overriding it', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - ['=A1'], - ['=$A1'], - ['=A$1'], - ['=$A$1'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A2'), 1, 4)) - engine.paste(adr('B1')) - - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.relative(-1, 0)) - expect(extractReference(engine, adr('B2'))).toEqual(CellAddress.absoluteCol(0, -1)) - expect(extractReference(engine, adr('B3'))).toEqual(CellAddress.absoluteRow(-1, 0)) - expect(extractReference(engine, adr('B4'))).toEqual(CellAddress.absolute(0, 0)) - }) - - it('should return #CYCLE when overriding referred dependency to external cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '1'], - ['=$B2', '2'], - ['=B$3', '3'], - ['=$B$4', '4'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 4)) - engine.paste(adr('B1')) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B3'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B4'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellFormula(adr('B1'))).toEqual('=B1') - expect(engine.getCellFormula(adr('B2'))).toEqual('=$B2') - expect(engine.getCellFormula(adr('B3'))).toEqual('=B$3') - expect(engine.getCellFormula(adr('B4'))).toEqual('=$B$4') - }) - - it('should work when overriding moved dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['=B2', '1'], - ['3', '2'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), adr('B1')) - - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(engine.getCellValue(adr('B2'))).toEqual(3) - }) - - it('should update internal dependency when overriding dependent cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=B$2', null], - [null, null], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('B2')) - - expect(extractReference(engine, adr('B2'))).toEqual(CellAddress.absoluteRow(1, 2)) - }) - - it('should update coordinates to internal dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ['2', '=$A2'], - ['3', '=A$3'], - ['4', '=$A$4'], - ]) - - expect(extractReference(engine, adr('B3'))).toEqual(CellAddress.absoluteRow(-1, 2)) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 4)) - engine.paste(adr('B2')) - - expect(extractReference(engine, adr('C2'))).toEqual(CellAddress.relative(-1, 0)) - expect(extractReference(engine, adr('C3'))).toEqual(CellAddress.absoluteCol(1, 0)) - expect(extractReference(engine, adr('C4'))).toEqual(CellAddress.absoluteRow(-1, 3)) - expect(extractReference(engine, adr('C5'))).toEqual(CellAddress.absolute(1, 4)) - }) - - it('should evaluate formula when overriding external formula dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(B1:B2)'], - ['=B3'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 3)) - engine.paste(adr('B1')) - - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - }) -}) - -describe('Move cells', () => { - it('should move static content', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - [null], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - expect(engine.getCellValue(adr('A2'))).toEqual('foo') - }) - - it('should update reference of moved formula when moving to other sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['foo'], - ['=A1'], - ], - Sheet2: [ - [null /* =A1 */], - ], - }) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A2'), 1, 1)) - engine.paste(adr('B1', 1)) - - expect(extractReference(engine, adr('B1', 1))).toEqual(CellAddress.relative(-1, 0)) - }) - - it('should update reference', () => { - const engine = HyperFormula.buildFromArray([ - ['foo' /* foo */], - ['=A1'], - ['=$A1'], - ['=A$1'], - ['=$A$1'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.relative(1, -1)) - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.absoluteCol(1, -2)) - expect(extractReference(engine, adr('A4'))).toEqual(CellAddress.absoluteRow(1, 0)) - expect(extractReference(engine, adr('A5'))).toEqual(CellAddress.absolute(1, 0)) - }) - - it('value moved has appropriate edges', () => { - const engine = HyperFormula.buildFromArray([ - ['foo' /* foo */], - ['=A1'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - const movedVertex = engine.dependencyGraph.fetchCell(adr('B1')) - expect(engine.graph.existsEdge(movedVertex, engine.dependencyGraph.fetchCell(adr('A2')))).toBe(true) - }) - - it('should update reference when moving to different sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['foo'], - ['=A1'], - ], - Sheet2: [], - }) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1', 1)) - - const reference = extractReference(engine, adr('A2')) - expect(reference).toEqual(CellAddress.relative(1, -1)) - }) - - it('should override and remove formula', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=A1'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - expect(graphEdgesCount(engine.graph)).toBe(0) - expect(engine.graph.getNodes().length).toBe(1) - expect(engine.getCellValue(adr('A1'))).toBe(null) - expect(engine.getCellValue(adr('A2'))).toBe(1) - }) - - it('moving empty vertex', () => { - const engine = HyperFormula.buildFromArray([ - [null, '42'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - expect(engine.addressMapping.getCell(adr('A1'))).toBe(undefined) - expect(engine.addressMapping.getCell(adr('B1'))).toBe(undefined) - }) - - it('replacing formula dependency with null one', () => { - const engine = HyperFormula.buildFromArray([ - [null, '42'], - ['=B1'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null], - ['=B1'], - ])) - }) - - it('moving empty vertex to empty vertex', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - expect(engine.addressMapping.getCell(adr('A1'))).toBe(undefined) - expect(engine.addressMapping.getCell(adr('B1'))).toBe(undefined) - }) - - it('should adjust edges properly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ['2', '=A2'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - const b1 = engine.addressMapping.getCell(adr('B1')) - const b2 = engine.addressMapping.getCell(adr('B2')) - const source = engine.addressMapping.getCell(adr('A1')) - const target = engine.addressMapping.getCell(adr('A2')) - - expect(graphEdgesCount(engine.graph)).toBe( - 2, // A2 -> B1, A2 -> B2 - ) - expect(engine.graph.getNodes().length).toBe( - +2 // formulas - + 1, // A2 - ) - - expect(source).toBe(undefined) - expect(engine.graph.existsEdge(target!, b2!)).toBe(true) - expect(engine.graph.existsEdge(target!, b1!)).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(1) - }) -}) - -describe('moving ranges', () => { - it('should not update range when only part of it is moved', () => { - const engine = HyperFormula.buildFromArray([ - ['1' /* 1 */], - ['2'], - ['=SUM(A1:A2)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - const range = extractRange(engine, adr('A3')) - expect(range.start).toEqual(adr('A1')) - expect(range.end).toEqual(adr('A2')) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - const a1a2 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) - expect(a1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a1!, a1a2)).toBe(true) - expect(engine.graph.existsEdge(a2!, a1a2)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1'], - ['2'], - ['=SUM(A1:A2)'], - ])) - }) - - it('should update moved range', () => { - const engine = HyperFormula.buildFromArray([ - ['1' /* 1 */], - ['2' /* 2 */], - ['=SUM(A1:A2)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2)) - engine.paste(adr('B1')) - - expect(engine.rangeMapping.getRangeVertex(adr('B1'), adr('B2'))).not.toBe(undefined) - - const range = extractRange(engine, adr('A3')) - expect(range.start).toEqual(adr('B1')) - expect(range.end).toEqual(adr('B2')) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - - expect(engine.addressMapping.getCell(adr('A1'))).toBe(undefined) - expect(engine.addressMapping.getCell(adr('A2'))).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1'], - [null, '2'], - ['=SUM(B1:B2)'], - ])) - }) - - it('should not be possible to move area with matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.cut(AbsoluteCellRange.spanFrom(adr('A2'), 2, 2)) - engine.paste(adr('C1')) - }).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should not be possible to move cells to area with matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1)) - engine.paste(adr('A2')) - }).toThrowError('Cannot perform this operation, target location has an array inside.') - }) - - it('should not be possible to cut when source is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - engine.cut({} as SimpleCellRange) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) - - it('should adjust edges when moving part of range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A2)'], - ['2', '=A2'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - const b1 = engine.addressMapping.getCell(adr('B1')) - const b2 = engine.addressMapping.getCell(adr('B2')) - const source = engine.addressMapping.getCell(adr('A1')) - const target = engine.addressMapping.getCell(adr('A2')) - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) - - expect(source).toBeInstanceOf(EmptyCellVertex) - expect(source!.getCellValue()).toBe(EmptyValue) - expect(engine.graph.getNodes().length).toBe( - +2 // formulas - + 1 // A2 - + 1 // A1 (Empty) - + 1, // A1:A2 range - ) - expect(graphEdgesCount(engine.graph)).toBe( - +2 // A1 (Empty) -> A1:A2, A2 -> A1:A2 - + 1 // A1:A2 -> B1 - + 1, // A2 -> B2 - ) - expect(engine.graph.existsEdge(target!, b2!)).toBe(true) - expect(engine.graph.existsEdge(source!, range)).toBe(true) - expect(engine.graph.existsEdge(target!, range)).toBe(true) - expect(engine.graph.existsEdge(range, b1!)).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(1) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '=SUM(A1:A2)'], - ['1', '=A2'], - ])) - }) - - it('should adjust edges when moving whole range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A2)'], - ['2', '=A2'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2)) - engine.paste(adr('C1')) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const c1 = engine.addressMapping.getCell(adr('C1')) - const c2 = engine.addressMapping.getCell(adr('C2')) - const range = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C2')) - - expect(a1).toBe(undefined) - expect(a2).toBe(undefined) - - expect(engine.graph.getNodes().length).toBe( - +2 // formulas - + 2 // C1, C2 - + 1, // C1:C2 range - ) - expect(graphEdgesCount(engine.graph)).toBe( - +2 // C1 -> C1:C2, C2 -> C1:C2 - + 1 // C1:C2 -> B1 - + 1, // C2 -> B2 - ) - - expect(engine.graph.existsEdge(c1!, range)).toBe(true) - expect(engine.graph.existsEdge(c2!, range)).toBe(true) - expect(engine.graph.existsEdge(range, b1!)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '=SUM(C1:C2)', '1'], - [null, '=C2', '2'], - ])) - }) - - it('should adjust edges when moving smaller range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null /* 1 */], - ['2', '=SUM(A1:A2)' /* 2 */], - ['3', '=SUM(A1:A3)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2)) - engine.paste(adr('C1')) - - /* ranges in formulas*/ - expect(extractRange(engine, adr('B2'))).toEqual(new AbsoluteCellRange( - adr('C1'), - adr('C2'), - )) - expect(extractRange(engine, adr('B3'))).toEqual(new AbsoluteCellRange( - adr('A1'), - adr('A3'), - )) - - /* edges */ - const c1c2 = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C2')) - const a1a3 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) - expect(engine.graph.existsEdge(c1c2, a1a3)).toBe(false) - - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A1'))!, a1a3)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A2'))!, a1a3)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A3'))!, a1a3)).toBe(true) - - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('C1'))!, c1c2)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('C2'))!, c1c2)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, '1'], - [null, '=SUM(C1:C2)', '2'], - ['3', '=SUM(A1:A3)'], - ])) - }) - - it('should adjust edges when moving smaller ranges - more complex', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null /* 1 */], - ['2', '=SUM(A1:A2)' /* 2 */], - ['3', '=SUM(A1:A3)' /* 3 */], - ['4', '=SUM(A1:A4)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 3)) - engine.paste(adr('C1')) - - /* edges */ - const c1c2 = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C2')) - const c1c3 = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C3')) - const a1a4 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A4')) - - expect(engine.graph.existsEdge(c1c2, c1c3)).toBe(true) - expect(engine.graph.existsEdge(c1c3, a1a4)).toBe(false) - - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A1'))!, a1a4)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A2'))!, a1a4)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A3'))!, a1a4)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A4'))!, a1a4)).toBe(true) - - const c1 = engine.addressMapping.getCell(adr('C1')) - const c2 = engine.addressMapping.getCell(adr('C2')) - const c3 = engine.addressMapping.getCell(adr('C3')) - expect(engine.graph.existsEdge(c1!, c1c2)).toBe(true) - expect(engine.graph.existsEdge(c2!, c1c2)).toBe(true) - expect(engine.graph.existsEdge(c1!, c1c3)).toBe(false) - expect(engine.graph.existsEdge(c2!, c1c3)).toBe(false) - expect(engine.graph.existsEdge(c3!, c1c3)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, '1'], - [null, '=SUM(C1:C2)', '2'], - [null, '=SUM(C1:C3)', '3'], - ['4', '=SUM(A1:A4)'], - ])) - }) - - it('move wider dependent ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(A1:B1)', '=SUM(A1:B2)', '=SUM(A1:B3)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('C1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, '1', '2'], - [null, null, '3', '4'], - ['5', '6'], - ['=SUM(C1:D1)', '=SUM(C1:D2)', '=SUM(A1:B3)'], - ])) - }) -}) - -describe('overlapping areas', () => { - it('overlapped rows', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('A2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null], - ['1', '2'], - ['3', '4'], - ])) - }) - - it('overlapped rows - opposite way', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A2'), 2, 2)) - engine.paste(adr('A1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['3', '4'], - ['5', '6'], - [null, null], - ])) - }) - - it('overlapped columns', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('B1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1', '2'], - [null, '4', '5'], - ])) - }) - - it('overlapped columns - opposite way', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('B1'), 2, 2)) - engine.paste(adr('A1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['2', '3', null], - ['5', '6', null], - ])) - }) - - it('moving along diagonal', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 3, 2)) - engine.paste(adr('B2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, null, null], - [null, '1', '2', '3'], - [null, '4', '5', '6'], - ])) - }) - - it('overlapped rows with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(A1:B2)', '=SUM(A1:B3)', '=SUM(A2:B2)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('A2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null], - ['1', '2'], - ['3', '4'], - ['=SUM(A2:B3)', '=SUM(A1:B3)', '=SUM(A3:B3)'], - ])) - }) - - it('overlapped columns with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=SUM(A1:B2)', '=SUM(A1:C2)', '=SUM(B1:B2)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('B1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1', '2'], - [null, '4', '5'], - ['=SUM(B1:C2)', '=SUM(A1:C2)', '=SUM(C1:C2)'], - ])) - }) - - it('expecting range to be same when moving part of a range inside this range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['=SUM(A1:A3)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null], - ['1'], - ['3'], - ['=SUM(A1:A3)'], - ])) - }) - - it('expecting range to be same when moving part of a range outside of this range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - [null], - ['=SUM(A1:A3)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A4')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null], - ['2'], - ['3'], - ['1'], - ['=SUM(A1:A3)'], - ])) - }) - - it('expecting range to be same when moving part of a range outside of this range - row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', null], - ['=SUM(A1:C1)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('D1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '2', '3', '1'], - ['=SUM(A1:C1)'], - ])) - }) - - it('ArrayFormulaVertex#formula should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('C1', 0)) - - expect(extractMatrixRange(engine, adr('A3'))).toEqual(new AbsoluteCellRange(adr('C1'), adr('D2'))) - }) - - it('ArrayFormulaVertex#formula should be updated when different sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['3', '4'], - ], - Sheet2: [ - ['=TRANSPOSE(Sheet1!A1:B2)'], - ], - }) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B2'))) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('C1', 0)) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('C1'), adr('D2'))) - }) -}) - -describe('column index', () => { - it('should update column index when moving cell', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['1'], - ['=VLOOKUP(1, A1:A2, 1, TRUE())'], - ], {useColumnIndex: true}) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('B1')) - - const index = engine.columnSearch as ColumnIndex - expectArrayWithSameContent([1, 2], index.getValueIndex(0, 0, 1).index) - expectArrayWithSameContent([0], index.getValueIndex(0, 1, 1).index) - }) - - it('should update column index when moving cell - REFs', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '1'], - ['3', '2'], - ], {useColumnIndex: true}) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2)) - engine.paste(adr('B1')) - - const index = engine.columnSearch as ColumnIndex - expectArrayWithSameContent([], index.getValueIndex(0, 0, 2).index) - expectArrayWithSameContent([], index.getValueIndex(0, 0, 3).index) - expectArrayWithSameContent([], index.getValueIndex(0, 1, 1).index) - expectArrayWithSameContent([1], index.getValueIndex(0, 1, 3).index) - }) - - it('should update column index when source and target overlaps', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '5'], - [null, '6', '7'], - ], {useColumnIndex: true}) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('B2')) - - const index = engine.columnSearch as ColumnIndex - expect(index.getColumnMap(0, 0).size).toEqual(0) - expect(index.getColumnMap(0, 1).size).toEqual(2) - expectArrayWithSameContent([1], index.getValueIndex(0, 1, 1).index) - expectArrayWithSameContent([2], index.getValueIndex(0, 1, 3).index) - expect(index.getColumnMap(0, 2).size).toEqual(2) - expectArrayWithSameContent([1], index.getValueIndex(0, 2, 2).index) - expectArrayWithSameContent([2], index.getValueIndex(0, 2, 4).index) - }) - - it('should update column index when source and target overlaps - oposite way', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '5'], - [null, '6', '7'], - ], {useColumnIndex: true}) - - engine.cut(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2)) - engine.paste(adr('A1')) - - const index = engine.columnSearch as ColumnIndex - expect(index.getColumnMap(0, 0).size).toEqual(2) - expectArrayWithSameContent([0], index.getValueIndex(0, 0, 4).index) - expectArrayWithSameContent([1], index.getValueIndex(0, 0, 6).index) - expect(index.getColumnMap(0, 0).size).toEqual(2) - expectArrayWithSameContent([0], index.getValueIndex(0, 1, 5).index) - expectArrayWithSameContent([1], index.getValueIndex(0, 1, 7).index) - expect(index.getColumnMap(0, 2).size).toEqual(0) - }) -}) - -describe('move cells with matrices', () => { - it('should not be possible to move part of formula matrix', function() { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.cut(AbsoluteCellRange.spanFrom(adr('A2'), 1, 1)) - engine.paste(adr('A3')) - }).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should not be possible to move formula matrix at all', function() { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.cut(AbsoluteCellRange.spanFrom(adr('A2'), 2, 1)) - engine.paste(adr('A3')) - }).toThrowError('Cannot perform this operation, source location has an array inside.') - }) -}) - -describe('aborting cut paste', () => { - it('should be aborted when addRows is done before paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'] - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.addRows(0, [1, 1]) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when removeRows is done before paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'] - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.removeRows(0, [1, 1]) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when addColumns is done before paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'] - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.addColumns(0, [1, 1]) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when removeColumns is done before paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'] - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.removeColumns(0, [1, 1]) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when moveCells is done before paste', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'] - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.moveCells(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1), adr('C1')) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when sheet is removed', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['1']], - 'Sheet2': [] - }) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.removeSheet(1) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when setCellContents is done', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.setCellContents(adr('B1'), 'foo') - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when sheet is cleared', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['1']], - 'Sheet2': [] - }) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.clearSheet(1) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when sheet content is replaced', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['1']], - 'Sheet2': [] - }) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.setSheetContent(1, []) - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should not be aborted when adding new sheet', () => { - const engine = HyperFormula.buildFromArray([['1']]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.addSheet() - - expect(engine.isClipboardEmpty()).toBe(false) - }) - - it('should not be aborted when addRows is not successful', () => { - const engine = HyperFormula.buildFromArray([['1']]) - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - - expect(() => { - engine.addRows(1, [1, 1]) - }).toThrow(new NoSheetWithIdError(1)) - - expect(engine.isClipboardEmpty()).toBe(false) - }) - - it('should be aborted when doing undo', () => { - const engine = HyperFormula.buildFromArray([['1']]) - engine.setCellContents(adr('A1'), 42) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - - engine.undo() - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when doing redo', () => { - const engine = HyperFormula.buildFromArray([['1']]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - - engine.redo() - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when swapping rows', () => { - const engine = HyperFormula.buildFromArray([['1']]) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.swapRowIndexes(0, [[0, 0]]) - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when swapping columns', () => { - const engine = HyperFormula.buildFromArray([['1']]) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.swapColumnIndexes(0, [[0, 0]]) - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when setting row order', () => { - const engine = HyperFormula.buildFromArray([['1']]) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.setRowOrder(0, [0]) - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('should be aborted when setting column order', () => { - const engine = HyperFormula.buildFromArray([['1']]) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.setColumnOrder(0, [0]) - expect(engine.isClipboardEmpty()).toBe(true) - }) -}) diff --git a/test/unit/cruds/move-cells.spec.ts b/test/unit/cruds/move-cells.spec.ts deleted file mode 100644 index e05a75742f..0000000000 --- a/test/unit/cruds/move-cells.spec.ts +++ /dev/null @@ -1,1118 +0,0 @@ -import {ErrorType, HyperFormula, SimpleCellAddress, SimpleCellRange} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {simpleCellAddress} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {EmptyCellVertex, ScalarFormulaVertex} from '../../../src/DependencyGraph' -import {SheetSizeLimitExceededError} from '../../../src/errors' -import {EmptyValue} from '../../../src/interpreter/InterpreterValue' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import {CellAddress} from '../../../src/parser' -import { - adr, - colEnd, - colStart, - detailedError, - expectArrayWithSameContent, - expectEngineToBeTheSameAs, - extractColumnRange, - extractMatrixRange, - extractRange, - extractReference, - extractRowRange, graphEdgesCount, - rowEnd, - rowStart, -} from '../testUtils' -import {ExpectedValueOfTypeError} from '../../../src/errors' - -describe('Moving rows - checking if its possible', () => { - it('source top left corner should have valid coordinates', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(simpleCellAddress(0, -1, 0), 1, 1), adr('A2'))).toEqual(false) - }) - - it('source top left corner should be in existing sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1', 1), 1, 1), adr('A2'))).toEqual(false) - }) - - it('target top left corner should have valid coordinates', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), simpleCellAddress(0, -1, 0))).toEqual(false) - }) - - it('target top left corner should be in existing sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2', 1))).toEqual(false) - }) - - it('no if we move the range which overlaps with matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - [], - ['13'], - ]) - - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2), adr('A10'))).toBe(false) - }) - - it('no if we move to range which overlaps with matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - [], - ['13'], - ]) - - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), adr('B2'))).toBe(false) - }) - - it('no if we move beyond sheet size limits', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ]) - - const cellInLastColumn = simpleCellAddress(0, Config.defaultConfig.maxColumns - 1, 0) - const cellInLastRow = simpleCellAddress(0, 0, Config.defaultConfig.maxRows - 1) - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), cellInLastColumn)).toEqual(true) - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1), cellInLastColumn)).toEqual(false) - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), cellInLastRow)).toEqual(true) - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), cellInLastRow)).toEqual(false) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2'))).toBe(true) - }) - - it('should throw error if testing with a source that is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - ]) - expect(() => { - engine.isItPossibleToMoveCells({} as SimpleCellRange, adr('A2')) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) - - it('should throw error if testing with a destinationLeftCorner that is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - ]) - expect(() => { - engine.isItPossibleToMoveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), {} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'destinationLeftCorner')) - }) -}) - -describe('Address dependencies, moved formulas', () => { - it('should update dependency to external cell when not overriding it', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - ['=A1'], - ['=$A1'], - ['=A$1'], - ['=$A$1'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A2'), 1, 4), adr('B1')) - - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.relative(-1, 0)) - expect(extractReference(engine, adr('B2'))).toEqual(CellAddress.absoluteCol(0, -1)) - expect(extractReference(engine, adr('B3'))).toEqual(CellAddress.absoluteRow(-1, 0)) - expect(extractReference(engine, adr('B4'))).toEqual(CellAddress.absolute(0, 0)) - }) - - it('should return #CYCLE when overriding referred dependency to external cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '1'], - ['=$B2', '2'], - ['=B$3', '3'], - ['=$B$4', '4'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 4), adr('B1')) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B3'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B4'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellFormula(adr('B1'))).toEqual('=B1') - expect(engine.getCellFormula(adr('B2'))).toEqual('=$B2') - expect(engine.getCellFormula(adr('B3'))).toEqual('=B$3') - expect(engine.getCellFormula(adr('B4'))).toEqual('=$B$4') - }) - - it('should work when overriding moved dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['=B2', '1'], - ['3', '2'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), adr('B1')) - - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(engine.getCellValue(adr('B2'))).toEqual(3) - }) - - it('should update internal dependency when overriding dependent cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=B$2', null], - [null, null], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('B2')) - - expect(extractReference(engine, adr('B2'))).toEqual(CellAddress.absoluteRow(1, 2)) - }) - - it('should update coordinates to internal dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ['2', '=$A2'], - ['3', '=A$3'], - ['4', '=$A$4'], - ]) - - expect(extractReference(engine, adr('B3'))).toEqual(CellAddress.absoluteRow(-1, 2)) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 4), adr('B2')) - - expect(extractReference(engine, adr('C2'))).toEqual(CellAddress.relative(-1, 0)) - expect(extractReference(engine, adr('C3'))).toEqual(CellAddress.absoluteCol(1, 0)) - expect(extractReference(engine, adr('C4'))).toEqual(CellAddress.absoluteRow(-1, 3)) - expect(extractReference(engine, adr('C5'))).toEqual(CellAddress.absolute(1, 4)) - }) - - it('should evaluate formula when overriding external formula dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(B1:B2)'], - ['=B3'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 3), adr('B1')) - - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - }) -}) - -describe('Move cells', () => { - it('should move static content', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - [null], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - expect(engine.getCellValue(adr('A2'))).toEqual('foo') - }) - - it('should update reference of moved formula when moving to other sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['foo'], - ['=A1'], - ], - Sheet2: [ - [null /* =A1 */], - ], - }) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A2'), 1, 1), adr('B1', 1)) - - expect(extractReference(engine, adr('B1', 1))).toEqual(CellAddress.relative(-1, 0)) - }) - - it('should update address in vertex', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['foo'], - ['=A1'], - ], - Sheet2: [ - [null /* =A1 */], - ], - }) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A2'), 1, 1), adr('B1', 1)) - - const vertex = engine.dependencyGraph.fetchCell(adr('B1', 1)) as ScalarFormulaVertex - expect(vertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('B1', 1)) - }) - - it('should update reference', () => { - const engine = HyperFormula.buildFromArray([ - ['foo' /* foo */], - ['=A1'], - ['=$A1'], - ['=A$1'], - ['=$A$1'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1')) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.relative(1, -1)) - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.absoluteCol(1, -2)) - expect(extractReference(engine, adr('A4'))).toEqual(CellAddress.absoluteRow(1, 0)) - expect(extractReference(engine, adr('A5'))).toEqual(CellAddress.absolute(1, 0)) - }) - - it('value moved has appropriate edges', () => { - const engine = HyperFormula.buildFromArray([ - ['foo' /* foo */], - ['=A1'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1')) - - const movedVertex = engine.dependencyGraph.fetchCell(adr('B1')) - expect(engine.graph.existsEdge(movedVertex, engine.dependencyGraph.fetchCell(adr('A2')))).toBe(true) - }) - - it('should update reference when moving to different sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['foo'], - ['=A1'], - ], - Sheet2: [], - }) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1', 1)) - - const reference = extractReference(engine, adr('A2')) - expect(reference).toEqual(CellAddress.relative(1, -1)) - }) - - it('should override and remove formula', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=A1'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - expect(graphEdgesCount(engine.graph)).toBe(0) - expect(engine.graph.getNodes().length).toBe(1) - expect(engine.getCellValue(adr('A1'))).toBe(null) - expect(engine.getCellValue(adr('A2'))).toBe(1) - }) - - it('moving empty vertex', () => { - const engine = HyperFormula.buildFromArray([ - [null, '42'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1')) - - expect(engine.addressMapping.getCell(adr('A1'))).toBe(undefined) - expect(engine.addressMapping.getCell(adr('B1'))).toBe(undefined) - }) - - it('replacing formula dependency with null one', () => { - const engine = HyperFormula.buildFromArray([ - [null, '42'], - ['=B1'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null], - ['=B1'], - ])) - }) - - it('moving empty vertex to empty vertex', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1')) - - expect(engine.addressMapping.getCell(adr('A1'))).toBe(undefined) - expect(engine.addressMapping.getCell(adr('B1'))).toBe(undefined) - }) - - it('should adjust edges properly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ['2', '=A2'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - const b1 = engine.addressMapping.getCell(adr('B1')) - const b2 = engine.addressMapping.getCell(adr('B2')) - const source = engine.addressMapping.getCell(adr('A1')) - const target = engine.addressMapping.getCell(adr('A2')) - - expect(graphEdgesCount(engine.graph)).toBe( - 2, // A2 -> B1, A2 -> B2 - ) - expect(engine.graph.getNodes().length).toBe( - +2 // formulas - + 1, // A2 - ) - - expect(source).toBe(undefined) - expect(engine.graph.existsEdge(target!, b2!)).toBe(true) - expect(engine.graph.existsEdge(target!, b1!)).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(1) - }) - - it('should throw error trying to move cells beyond sheet limits', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ]) - - const cellInLastColumn = simpleCellAddress(0, Config.defaultConfig.maxColumns - 1, 0) - const cellInLastRow = simpleCellAddress(0, 0, Config.defaultConfig.maxRows - 1) - - expect(() => engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1), cellInLastColumn)).toThrow(new SheetSizeLimitExceededError()) - expect(() => engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), cellInLastRow)).toThrow(new SheetSizeLimitExceededError()) - }) - - it('should throw error trying to move cells when source is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - ]) - expect(() => { - engine.moveCells({} as SimpleCellRange, adr('A2')) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) - - it('should throw error trying to move cells when destinationLeftCorner is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([ - [null, null], - ]) - expect(() => { - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), {} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'destinationLeftCorner')) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards', () => { - const engine = HyperFormula.buildFromArray([[null, '=A1', 42]]) - engine.moveCells({ start: adr('B1'), end: adr('B1')}, adr('A1')) - engine.setCellContents(adr('A1'), '=A2') - expect(engine.getSheetSerialized(0)).toEqual([['=A2', null, 42]]) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards (with a range)', () => { - const engine = HyperFormula.buildFromArray([[null, null, null, '=SUM(A1:C1)', 42]]) - engine.moveCells({ start: adr('D1'), end: adr('D1')}, adr('A1')) - engine.setCellContents(adr('A1'), '=SUM(B1:D1)') - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(B1:D1)', null, null, null, 42]]) - }) -}) - -describe('moving ranges', () => { - it('should not update range when only part of it is moved', () => { - const engine = HyperFormula.buildFromArray([ - ['1' /* 1 */], - ['2'], - ['=SUM(A1:A2)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1')) - - const range = extractRange(engine, adr('A3')) - expect(range.start).toEqual(adr('A1')) - expect(range.end).toEqual(adr('A2')) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - const a1a2 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) - expect(a1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a1!, a1a2)).toBe(true) - expect(engine.graph.existsEdge(a2!, a1a2)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1'], - ['2'], - ['=SUM(A1:A2)'], - ])) - }) - - it('should update moved range', () => { - const engine = HyperFormula.buildFromArray([ - ['1' /* 1 */], - ['2' /* 2 */], - ['=SUM(A1:A2)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), adr('B1')) - - expect(engine.rangeMapping.getRangeVertex(adr('B1'), adr('B2'))).not.toBe(undefined) - - const range = extractRange(engine, adr('A3')) - expect(range.start).toEqual(adr('B1')) - expect(range.end).toEqual(adr('B2')) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - - expect(engine.addressMapping.getCell(adr('A1'))).toBe(undefined) - expect(engine.addressMapping.getCell(adr('A2'))).toBe(undefined) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1'], - [null, '2'], - ['=SUM(B1:B2)'], - ])) - }) - - it('should not be possible to move area with matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A2'), 2, 2), adr('C1')) - }).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should not be possible to move cells to area with matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1), adr('A2')) - }).toThrowError('Cannot perform this operation, target location has an array inside.') - }) - - it('should adjust edges when moving part of range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A2)'], - ['2', '=A2'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - const b1 = engine.addressMapping.getCell(adr('B1')) - const b2 = engine.addressMapping.getCell(adr('B2')) - const source = engine.addressMapping.getCell(adr('A1')) - const target = engine.addressMapping.getCell(adr('A2')) - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) - - expect(source).toBeInstanceOf(EmptyCellVertex) - expect(source!.getCellValue()).toBe(EmptyValue) - expect(engine.graph.getNodes().length).toBe( - +2 // formulas - + 1 // A2 - + 1 // A1 (Empty) - + 1, // A1:A2 range - ) - expect(graphEdgesCount(engine.graph)).toBe( - +2 // A1 (Empty) -> A1:A2, A2 -> A1:A2 - + 1 // A1:A2 -> B1 - + 1, // A2 -> B2 - ) - expect(engine.graph.existsEdge(target!, b2!)).toBe(true) - expect(engine.graph.existsEdge(source!, range)).toBe(true) - expect(engine.graph.existsEdge(target!, range)).toBe(true) - expect(engine.graph.existsEdge(range, b1!)).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(1) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '=SUM(A1:A2)'], - ['1', '=A2'], - ])) - }) - - it('should adjust edges when moving whole range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A2)'], - ['2', '=A2'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), adr('C1')) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const c1 = engine.addressMapping.getCell(adr('C1')) - const c2 = engine.addressMapping.getCell(adr('C2')) - const range = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C2')) - - expect(a1).toBe(undefined) - expect(a2).toBe(undefined) - - expect(engine.graph.getNodes().length).toBe( - +2 // formulas - + 2 // C1, C2 - + 1, // C1:C2 range - ) - expect(graphEdgesCount(engine.graph)).toBe( - +2 // C1 -> C1:C2, C2 -> C1:C2 - + 1 // C1:C2 -> B1 - + 1, // C2 -> B2 - ) - - expect(engine.graph.existsEdge(c1!, range)).toBe(true) - expect(engine.graph.existsEdge(c2!, range)).toBe(true) - expect(engine.graph.existsEdge(range, b1!)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '=SUM(C1:C2)', '1'], - [null, '=C2', '2'], - ])) - }) - - it('should adjust edges when moving smaller range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null /* 1 */], - ['2', '=SUM(A1:A2)' /* 2 */], - ['3', '=SUM(A1:A3)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), adr('C1')) - - /* ranges in formulas*/ - expect(extractRange(engine, adr('B2'))).toEqual(new AbsoluteCellRange( - adr('C1'), - adr('C2'), - )) - expect(extractRange(engine, adr('B3'))).toEqual(new AbsoluteCellRange( - adr('A1'), - adr('A3'), - )) - - /* edges */ - const c1c2 = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C2')) - const a1a3 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) - expect(engine.graph.existsEdge(c1c2, a1a3)).toBe(false) - - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A1'))!, a1a3)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A2'))!, a1a3)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A3'))!, a1a3)).toBe(true) - - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('C1'))!, c1c2)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('C2'))!, c1c2)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, '1'], - [null, '=SUM(C1:C2)', '2'], - ['3', '=SUM(A1:A3)'], - ])) - }) - - it('should adjust edges when moving smaller ranges - more complex', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null /* 1 */], - ['2', '=SUM(A1:A2)' /* 2 */], - ['3', '=SUM(A1:A3)' /* 3 */], - ['4', '=SUM(A1:A4)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 3), adr('C1')) - - /* edges */ - const c1c2 = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C2')) - const c1c3 = engine.rangeMapping.getVertexOrThrow(adr('C1'), adr('C3')) - const a1a4 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A4')) - - expect(engine.graph.existsEdge(c1c2, c1c3)).toBe(true) - expect(engine.graph.existsEdge(c1c3, a1a4)).toBe(false) - - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A1'))!, a1a4)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A2'))!, a1a4)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A3'))!, a1a4)).toBe(true) - expect(engine.graph.existsEdge(engine.addressMapping.getCell(adr('A4'))!, a1a4)).toBe(true) - - const c1 = engine.addressMapping.getCell(adr('C1')) - const c2 = engine.addressMapping.getCell(adr('C2')) - const c3 = engine.addressMapping.getCell(adr('C3')) - expect(engine.graph.existsEdge(c1!, c1c2)).toBe(true) - expect(engine.graph.existsEdge(c2!, c1c2)).toBe(true) - expect(engine.graph.existsEdge(c1!, c1c3)).toBe(false) - expect(engine.graph.existsEdge(c2!, c1c3)).toBe(false) - expect(engine.graph.existsEdge(c3!, c1c3)).toBe(true) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, '1'], - [null, '=SUM(C1:C2)', '2'], - [null, '=SUM(C1:C3)', '3'], - ['4', '=SUM(A1:A4)'], - ])) - }) - - it('move wider dependent ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(A1:B1)', '=SUM(A1:B2)', '=SUM(A1:B3)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('C1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, '1', '2'], - [null, null, '3', '4'], - ['5', '6'], - ['=SUM(C1:D1)', '=SUM(C1:D2)', '=SUM(A1:B3)'], - ])) - }) -}) - -describe('overlapping areas', () => { - it('overlapped rows', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('A2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null], - ['1', '2'], - ['3', '4'], - ])) - }) - - it('overlapped rows - opposite way', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A2'), 2, 2), adr('A1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['3', '4'], - ['5', '6'], - [null, null], - ])) - }) - - it('overlapped columns', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('B1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1', '2'], - [null, '4', '5'], - ])) - }) - - it('overlapped columns - opposite way', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('B1'), 2, 2), adr('A1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['2', '3', null], - ['5', '6', null], - ])) - }) - - it('moving along diagonal', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 3, 2), adr('B2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null, null, null], - [null, '1', '2', '3'], - [null, '4', '5', '6'], - ])) - }) - - it('overlapped rows with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=SUM(A1:B2)', '=SUM(A1:B3)', '=SUM(A2:B2)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('A2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, null], - ['1', '2'], - ['3', '4'], - ['=SUM(A2:B3)', '=SUM(A1:B3)', '=SUM(A3:B3)'], - ])) - }) - - it('overlapped columns with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=SUM(A1:B2)', '=SUM(A1:C2)', '=SUM(B1:B2)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('B1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '1', '2'], - [null, '4', '5'], - ['=SUM(B1:C2)', '=SUM(A1:C2)', '=SUM(C1:C2)'], - ])) - }) - - it('expecting range to be same when moving part of a range inside this range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['=SUM(A1:A3)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null], - ['1'], - ['3'], - ['=SUM(A1:A3)'], - ])) - }) - - it('expecting range to be same when moving part of a range outside of this range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - [null], - ['=SUM(A1:A3)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A4')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null], - ['2'], - ['3'], - ['1'], - ['=SUM(A1:A3)'], - ])) - }) - - it('expecting range to be same when moving part of a range outside of this range - row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', null], - ['=SUM(A1:C1)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('D1')) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null, '2', '3', '1'], - ['=SUM(A1:C1)'], - ])) - }) - - it('ArrayFormulaVertex#formula should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('C1', 0)) - - expect(extractMatrixRange(engine, adr('A3'))).toEqual(new AbsoluteCellRange(adr('C1'), adr('D2'))) - }) - - it('ArrayFormulaVertex#formula should be updated when different sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['3', '4'], - ], - Sheet2: [ - ['=TRANSPOSE(Sheet1!A1:B2)'], - ], - }) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B2'))) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('C1', 0)) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('C1'), adr('D2'))) - }) - - it('overlapped formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2'], - ['42'] - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null], - ['=A2'] - ])) - }) - - it('overlapped formula with range', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2:B2'], - ['42'] - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [null], - ['=A2:B2'] - ])) - }) -}) - -describe('column index', () => { - it('should update column index when moving cell', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['1'], - ['=VLOOKUP(1, A1:A2, 1, TRUE())'], - ], {useColumnIndex: true}) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B1')) - - const index = engine.columnSearch as ColumnIndex - expectArrayWithSameContent([1, 2], index.getValueIndex(0, 0, 1).index) - expectArrayWithSameContent([0], index.getValueIndex(0, 1, 1).index) - }) - - it('should update column index when moving cell - REFs', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '1'], - ['3', '2'], - ], {useColumnIndex: true}) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 2), adr('B1')) - - const index = engine.columnSearch as ColumnIndex - expectArrayWithSameContent([], index.getValueIndex(0, 0, 2).index) - expectArrayWithSameContent([], index.getValueIndex(0, 0, 3).index) - expectArrayWithSameContent([], index.getValueIndex(0, 1, 1).index) - expectArrayWithSameContent([], index.getValueIndex(0, 1, 2).index) - expectArrayWithSameContent([1], index.getValueIndex(0, 1, 3).index) - }) - - it('should update column index when source and target overlaps', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '5'], - [null, '6', '7'], - ], {useColumnIndex: true}) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), adr('B2')) - - const index = engine.columnSearch as ColumnIndex - expect(index.getColumnMap(0, 0).size).toEqual(0) - expect(index.getColumnMap(0, 1).size).toEqual(2) - expectArrayWithSameContent([1], index.getValueIndex(0, 1, 1).index) - expectArrayWithSameContent([2], index.getValueIndex(0, 1, 3).index) - expect(index.getColumnMap(0, 2).size).toEqual(2) - expectArrayWithSameContent([1], index.getValueIndex(0, 2, 2).index) - expectArrayWithSameContent([2], index.getValueIndex(0, 2, 4).index) - }) - - it('should update column index when source and target overlaps - oposite way', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4', '5'], - [null, '6', '7'], - ], {useColumnIndex: true}) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2), adr('A1')) - - const index = engine.columnSearch as ColumnIndex - expect(index.getColumnMap(0, 0).size).toEqual(2) - expectArrayWithSameContent([0], index.getValueIndex(0, 0, 4).index) - expectArrayWithSameContent([1], index.getValueIndex(0, 0, 6).index) - expect(index.getColumnMap(0, 0).size).toEqual(2) - expectArrayWithSameContent([0], index.getValueIndex(0, 1, 5).index) - expectArrayWithSameContent([1], index.getValueIndex(0, 1, 7).index) - expect(index.getColumnMap(0, 2).size).toEqual(0) - }) -}) - -describe('move cells with matrices', () => { - it('should not be possible to move part of formula matrix', function() { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A2'), 1, 1), adr('A3')) - }).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should not be possible to move formula matrix at all', function() { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(() => { - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A2'), 2, 1), adr('A3')) - }).toThrowError('Cannot perform this operation, source location has an array inside.') - }) -}) - -describe('cell ranges', () => { - it('should transform relative references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, '=SUM(A1:B1)', '=SUM($A1:B$1)', '=SUM(A$1:$B$1)']]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('C1'), 3, 1), adr('D2')) - - expect(engine.getCellFormula(adr('D2'))).toEqual('=SUM(A1:B1)') - expect(engine.getCellFormula(adr('E2'))).toEqual('=SUM($A1:B$1)') - expect(engine.getCellFormula(adr('F2'))).toEqual('=SUM(A$1:$B$1)') - }) - - it('move formula and one end of a range', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [null, '=SUM(A1:B1)'] - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('B1'), 1, 2), adr('C1')) - - expect(engine.getCellFormula(adr('C2'))).toEqual('=SUM(A1:B1)') - }) - - it('should be #CYCLE! if one of ends is in target range', () => { - const engine = HyperFormula.buildFromArray([[1, 2, '=SUM(A1:B1)']]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('C1'), 1, 1), adr('B1')) - - expect(engine.getCellFormula(adr('B1'))).toEqual('=SUM(A1:B1)') - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) -}) - -describe('column ranges', () => { - it('should not update range when only part of it is moved', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '3', '=SUM(A:B)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('C2')) - - const range = extractColumnRange(engine, adr('C1')) - expect(range.start).toEqual(colStart('A')) - expect(range.end).toEqual(colEnd('B')) - expect(engine.getCellValue(adr('C1'))).toEqual(3) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const ab = engine.rangeMapping.getVertexOrThrow(colStart('A'), colEnd('B')) - expect(a1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a1!, ab)).toBe(true) - expect(engine.graph.existsEdge(b1!, ab)).toBe(true) - }) - - it('should transform relative column references', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(C:D)', '', '1', '2'] - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B2')) - - const range = extractColumnRange(engine, adr('B2')) - expect(engine.getCellValue(adr('B2'))).toEqual(3) - expect(range.start).toEqual(colStart('C')) - expect(range.end).toEqual(colEnd('D')) - }) - - it('should be #CYCLE! if one of ends is in target range', () => { - const engine = HyperFormula.buildFromArray([[1, 2, '=SUM(A:B)']]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('C1'), 1, 1), adr('B1')) - - expect(engine.getCellFormula(adr('B1'))).toEqual('=SUM(A:B)') - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) -}) - -describe('row ranges', () => { - it('should not update range when only part of it is moved', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['3'], - ['=SUM(1:2)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B3')) - - const range = extractRowRange(engine, adr('A3')) - expect(range.start).toEqual(rowStart(1)) - expect(range.end).toEqual(rowEnd(2)) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - const ab = engine.rangeMapping.getVertexOrThrow(rowStart(1), rowEnd(2)) - expect(a1).toBeInstanceOf(EmptyCellVertex) - expect(engine.graph.existsEdge(a1!, ab)).toBe(true) - expect(engine.graph.existsEdge(a2!, ab)).toBe(true) - }) - - it('should transform relative column references', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(3:4)'], - [null], - ['1'], - ['2'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('B2')) - - const range = extractRowRange(engine, adr('B2')) - expect(engine.getCellValue(adr('B2'))).toEqual(3) - expect(range.start).toEqual(rowStart(3)) - expect(range.end).toEqual(rowEnd(4)) - }) - - it('should be #CYCLE! if one of ends is in target range', () => { - const engine = HyperFormula.buildFromArray([ - [1], - [2], - ['=SUM(1:2)'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A3'), 1, 1), adr('A2')) - - expect(engine.getCellFormula(adr('A2'))).toEqual('=SUM(1:2)') - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) -}) diff --git a/test/unit/cruds/move-columns.spec.ts b/test/unit/cruds/move-columns.spec.ts deleted file mode 100644 index 0e4a69cc56..0000000000 --- a/test/unit/cruds/move-columns.spec.ts +++ /dev/null @@ -1,331 +0,0 @@ -import {ExportedCellChange, HyperFormula, InvalidArgumentsError} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {CellAddress} from '../../../src/parser' -import { - adr, - colEnd, - colStart, - detailedError, - extractColumnRange, - extractReference, - extractRowRange, - rowEnd, - rowStart -} from '../testUtils' - -describe('Ensure it is possible to move columns', () => { - it('should return false when target makes no sense', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ]) - - expect(engine.isItPossibleToMoveColumns(0, 0, 1, -1)).toEqual(false) - expect(engine.isItPossibleToMoveColumns(0, 0, 1, 1)).toEqual(false) - expect(engine.isItPossibleToMoveColumns(0, 0, 1, 0)).toEqual(false) - expect(engine.isItPossibleToMoveColumns(0, 0, 2, 0)).toEqual(false) - expect(engine.isItPossibleToMoveColumns(0, 0, 2, 1)).toEqual(false) - expect(engine.isItPossibleToMoveColumns(0, 0, 2, 2)).toEqual(false) - }) - - it('should not be possible to move columns when sheet does not exists', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ]) - - expect(engine.isItPossibleToMoveColumns(1, 0, 1, 2)).toEqual(false) - }) - - it('should not be possible to move columns when number of columns is non-positive', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - - expect(engine.isItPossibleToMoveColumns(0, 0, 0, 1)).toEqual(false) - expect(engine.isItPossibleToMoveColumns(0, 0, -5, 1)).toEqual(false) - }) - - it('should be possible to move columns', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '1', '2'], - ]) - - expect(engine.isItPossibleToMoveColumns(0, 1, 1, 0)).toEqual(true) - expect(engine.isItPossibleToMoveColumns(0, 1, 1, 3)).toEqual(true) - expect(engine.isItPossibleToMoveColumns(0, 1, 1, 4)).toEqual(true) - expect(engine.isItPossibleToMoveColumns(0, 1, 2, 0)).toEqual(true) - expect(engine.isItPossibleToMoveColumns(0, 1, 2, 4)).toEqual(true) - expect(engine.isItPossibleToMoveColumns(0, 1, 2, 5)).toEqual(true) - }) - - it('should not be possible to move row with formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=TRANSPOSE(A1:A2)'], - ['2'], - ]) - - expect(engine.isItPossibleToMoveColumns(0, 1, 1, 5)).toBe(false) - expect(engine.isItPossibleToMoveColumns(0, 1, 2, 5)).toBe(false) - }) - - it('should not be possible to move row inside formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '', '=TRANSPOSE(A1:A2)'], - ['2'], - ]) - - expect(engine.isItPossibleToMoveColumns(0, 0, 1, 2)).toBe(true) - expect(engine.isItPossibleToMoveColumns(0, 0, 1, 3)).toBe(false) - expect(engine.isItPossibleToMoveColumns(0, 0, 1, 4)).toBe(true) - }) -}) - -describe('Move columns', () => { - it('should throw error when target makes no sense', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ]) - - expect(() => engine.moveColumns(0, 0, 1, -1)).toThrow(new InvalidArgumentsError('column number to be nonnegative and number of columns to add to be positive.')) - expect(() => engine.moveColumns(0, 0, 1, 1)).toThrow(new InvalidArgumentsError('a valid range of columns to move.')) - expect(() => engine.moveColumns(0, 0, 1, 0)).toThrow(new InvalidArgumentsError('a valid range of columns to move.')) - expect(() => engine.moveColumns(0, 0, 2, 0)).toThrow(new InvalidArgumentsError('a valid range of columns to move.')) - expect(() => engine.moveColumns(0, 0, 2, 1)).toThrow(new InvalidArgumentsError('a valid range of columns to move.')) - expect(() => engine.moveColumns(0, 0, 2, 2)).toThrow(new InvalidArgumentsError('a valid range of columns to move.')) - }) - - it('should move one column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4'] - ]) - - engine.moveColumns(0, 1, 1, 3) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(engine.getCellValue(adr('C1'))).toEqual(2) - expect(engine.getCellValue(adr('D1'))).toEqual(4) - }) - - it('should move column when moving to left', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4'] - ]) - - engine.moveColumns(0, 2, 1, 1) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(engine.getCellValue(adr('C1'))).toEqual(2) - expect(engine.getCellValue(adr('D1'))).toEqual(4) - }) - - it('should move multiple columns', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4'] - ]) - - engine.moveColumns(0, 0, 3, 4) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(2) - expect(engine.getCellValue(adr('D1'))).toEqual(3) - }) - - it('should work when moving multiple columns far away', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'] - ]) - - engine.moveColumns(0, 1, 2, 5) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toBe(null) - expect(engine.getCellValue(adr('C1'))).toBe(null) - expect(engine.getCellValue(adr('D1'))).toEqual(2) - expect(engine.getCellValue(adr('E1'))).toEqual(3) - }) - - it('should adjust reference when swapping formula with dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1'], - ['=B2', '1'], - ]) - - engine.moveColumns(0, 1, 1, 0) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('B2'))).toEqual(1) - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(1, 0)) - expect(extractReference(engine, adr('B2'))).toEqual(CellAddress.relative(-1, 0)) - }) - - it('should adjust absolute references', () => { - const engine = HyperFormula.buildFromArray([ - ['=$B$1'], - ['=B2'] - ]) - - engine.moveColumns(0, 0, 1, 2) - - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.absolute(0, 0)) - expect(extractReference(engine, adr('B2'))).toEqual(CellAddress.relative(-1, 0)) - }) - - it('should adjust range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['', '=COUNTBLANK(A1:B1)'], - ]) - - engine.moveColumns(0, 1, 1, 3) - - expect(engine.getCellFormula(adr('C2'))).toEqual('=COUNTBLANK(A1:A1)') - expect(engine.getCellValue(adr('C2'))).toEqual(0) - }) - - it('should return changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - ['', '=COUNTBLANK(A1:B1)'], - ]) - - const changes = engine.moveColumns(0, 1, 1, 3) - - expect(changes.length).toEqual(1) - expect(changes).toContainEqual(new ExportedCellChange(adr('C2'), 0)) - }) - - it('should return #CYCLE when moving formula onto referred range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=AVERAGE(A1:C1)', '=SUM(A1:C1)'] - ]) - - engine.moveColumns(0, 3, 1, 1) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) - - it('should work with moving formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4', '=SUM(A1:C1)'] - ]) - - engine.moveColumns(0, 3, 1, 1) - - expect(engine.getCellValue(adr('E1'))).toEqual(10) - }) - - it('should return #CYCLE when moving formula onto referred range, simple case', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B1:C1)', '1', '2'] - ]) - - engine.moveColumns(0, 0, 1, 2) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellFormula(adr('B1'))).toEqual('=SUM(A1:C1)') - }) - - it('should produce only one history entry', () => { - const engine = HyperFormula.buildFromArray([[0, 1, 2, 3]]) - - const version = engine.lazilyTransformingAstService.version() - - engine.moveColumns(0, 1, 1, 3) - - expect(engine.lazilyTransformingAstService.version()).toEqual(version + 1) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards', () => { - const engine = HyperFormula.buildFromArray([[ null, '=A1' ]]) - engine.moveColumns(0, 1, 1, 0) - expect(engine.getCellSerialized(adr('A1'))).toEqual('=B1') - expect(engine.getCellSerialized(adr('B1'))).toEqual(null) - - engine.setCellContents(adr('A1'), '=B1') - expect(engine.getCellSerialized(adr('A1'))).toEqual('=B1') - expect(engine.getCellSerialized(adr('B1'))).toEqual(null) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards (with a range)', () => { - const engine = HyperFormula.buildFromArray([[null, null, null, '=SUM(A1:C1)', 42]]) - engine.moveColumns(0, 3, 1, 0) - engine.setCellContents(adr('A1'), '=SUM(B1:D1)') - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(B1:D1)', null, null, null, 42]]) - }) -}) - -describe('Move columns - column ranges', () => { - it('should adjust relative references of dependent formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B:C)', '1', '2'] - ]) - - engine.moveColumns(0, 1, 2, 4) - - const range = extractColumnRange(engine, adr('A1')) - expect(range.start).toEqual(colStart('C')) - expect(range.end).toEqual(colEnd('D')) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should adjust relative dependencies of moved formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B:C)', '1', '2'] - ]) - - engine.moveColumns(0, 0, 1, 3) - - const range = extractColumnRange(engine, adr('C1')) - expect(range.start).toEqual(colStart('A')) - expect(range.end).toEqual(colEnd('B')) - expect(engine.getCellValue(adr('C1'))).toEqual(3) - }) - - it('should return #CYCLE when moving formula onto referred range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B:C)', '1', '2'] - ]) - - engine.moveColumns(0, 0, 1, 2) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellFormula(adr('B1'))).toEqual('=SUM(A:C)') - }) -}) - -describe('Move columns - row ranges', () => { - it('should not affect moved row range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2:3)'], - ['1'], - ['2'] - ]) - - engine.moveColumns(0, 0, 1, 2) - - const range = extractRowRange(engine, adr('B1')) - expect(range.start).toEqual(rowStart(2)) - expect(range.end).toEqual(rowEnd(3)) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) - - it('should not affect dependent row range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2:3)'], - ['1', '3'], - ['2', '4'] - ]) - - engine.moveColumns(0, 1, 1, 3) - - const range = extractRowRange(engine, adr('A1')) - expect(range.start).toEqual(rowStart(2)) - expect(range.end).toEqual(rowEnd(3)) - expect(engine.getCellValue(adr('A1'))).toEqual(10) - }) -}) diff --git a/test/unit/cruds/move-rows.spec.ts b/test/unit/cruds/move-rows.spec.ts deleted file mode 100644 index 9d43d45d8f..0000000000 --- a/test/unit/cruds/move-rows.spec.ts +++ /dev/null @@ -1,326 +0,0 @@ -import {ExportedCellChange, HyperFormula, InvalidArgumentsError} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {CellAddress} from '../../../src/parser' -import { - adr, - colEnd, - colStart, - detailedError, - extractColumnRange, - extractReference, - extractRowRange, - rowEnd, - rowStart, -} from '../testUtils' - -describe('Ensure it is possible to move rows', () => { - it('should return false when target makes no sense', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'] - ]) - - expect(engine.isItPossibleToMoveRows(0, 0, 1, -1)).toEqual(false) - expect(engine.isItPossibleToMoveRows(0, 0, 1, 1)).toEqual(false) - expect(engine.isItPossibleToMoveRows(0, 0, 1, 0)).toEqual(false) - expect(engine.isItPossibleToMoveRows(0, 0, 2, 0)).toEqual(false) - expect(engine.isItPossibleToMoveRows(0, 0, 2, 1)).toEqual(false) - expect(engine.isItPossibleToMoveRows(0, 0, 2, 2)).toEqual(false) - }) - - it('should not be possible to move rows when sheet does not exists', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ]) - - expect(engine.isItPossibleToMoveRows(1, 0, 1, 2)).toEqual(false) - }) - - it('should not be possible to move rows when number of rows is non-positive', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - - expect(engine.isItPossibleToMoveRows(0, 0, 0, 1)).toEqual(false) - expect(engine.isItPossibleToMoveRows(0, 0, -5, 1)).toEqual(false) - }) - - it('should be possible to move rows', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['2'], - ]) - - expect(engine.isItPossibleToMoveRows(0, 1, 1, 0)).toEqual(true) - expect(engine.isItPossibleToMoveRows(0, 1, 1, 3)).toEqual(true) - expect(engine.isItPossibleToMoveRows(0, 1, 1, 4)).toEqual(true) - expect(engine.isItPossibleToMoveRows(0, 1, 2, 0)).toEqual(true) - expect(engine.isItPossibleToMoveRows(0, 1, 2, 4)).toEqual(true) - expect(engine.isItPossibleToMoveRows(0, 1, 2, 5)).toEqual(true) - }) - - it('should not be possible to move row with formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(engine.isItPossibleToMoveRows(0, 1, 1, 5)).toBe(false) - expect(engine.isItPossibleToMoveRows(0, 1, 2, 5)).toBe(false) - }) - - it('should not be possible to move row inside formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - [''], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(engine.isItPossibleToMoveRows(0, 0, 1, 2)).toBe(true) - expect(engine.isItPossibleToMoveRows(0, 0, 1, 3)).toBe(false) - expect(engine.isItPossibleToMoveRows(0, 0, 1, 4)).toBe(true) - }) -}) - -describe('Move rows', () => { - it('should throw error when target makes no sense', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'] - ]) - - expect(() => engine.moveRows(0, 0, 1, -1)).toThrow(new InvalidArgumentsError('row number to be nonnegative and number of rows to add to be positive.')) - expect(() => engine.moveRows(0, 0, 1, 1)).toThrow(new InvalidArgumentsError('a valid range of rows to move.')) - expect(() => engine.moveRows(0, 0, 1, 0)).toThrow(new InvalidArgumentsError('a valid range of rows to move.')) - expect(() => engine.moveRows(0, 0, 2, 0)).toThrow(new InvalidArgumentsError('a valid range of rows to move.')) - expect(() => engine.moveRows(0, 0, 2, 1)).toThrow(new InvalidArgumentsError('a valid range of rows to move.')) - expect(() => engine.moveRows(0, 0, 2, 2)).toThrow(new InvalidArgumentsError('a valid range of rows to move.')) - }) - - it('should move one row', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['4'], - ]) - - engine.moveRows(0, 1, 1, 3) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('should move row when moving upward', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['4'], - ]) - - engine.moveRows(0, 2, 1, 1) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('should move multiple rows', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['4'], - ]) - - engine.moveRows(0, 0, 3, 4) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('should work when moving multiple rows far away', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ]) - - engine.moveRows(0, 1, 2, 5) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toBe(null) - expect(engine.getCellValue(adr('A3'))).toBe(null) - expect(engine.getCellValue(adr('A4'))).toEqual(2) - expect(engine.getCellValue(adr('A5'))).toEqual(3) - }) - - it('should adjust reference when swapping formula with dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=A1'], - ]) - - engine.moveRows(0, 1, 1, 0) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 1)) - }) - - it('should adjust absolute references', () => { - const engine = HyperFormula.buildFromArray([ - ['=$A$2', '=B2'] - ]) - - engine.moveRows(0, 0, 1, 2) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.absolute(0, 0)) - expect(extractReference(engine, adr('B2'))).toEqual(CellAddress.relative(0, -1)) - }) - - it('should adjust range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2', '=COUNTBLANK(A1:A2)'], - ]) - - engine.moveRows(0, 1, 1, 3) - - expect(engine.getCellFormula(adr('B3'))).toEqual('=COUNTBLANK(A1:A1)') - expect(engine.getCellValue(adr('B3'))).toEqual(0) - }) - - it('should return changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - [null, '=COUNTBLANK(A1:A2)'], - ]) - - const changes = engine.moveRows(0, 1, 1, 3) - - expect(changes.length).toEqual(1) - expect(changes).toContainEqual(new ExportedCellChange(adr('B3'), 0)) - }) - - it('should return #CYCLE when moving formula onto referred range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['=SUM(A1:A3)'], - ['=AVERAGE(A1:A3)'], - ]) - - engine.moveRows(0, 3, 1, 1) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) - - it('should produce only one history entry', () => { - const engine = HyperFormula.buildFromArray([[0], [1], [2], [3]]) - - const version = engine.lazilyTransformingAstService.version() - - engine.moveRows(0, 1, 1, 3) - - expect(engine.lazilyTransformingAstService.version()).toEqual(version + 1) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards', () => { - const engine = HyperFormula.buildFromArray([[null], ['=A1']]) - engine.moveRows(0, 1, 1, 0) - engine.setCellContents(adr('A1'), '=A2') - expect(engine.getSheetSerialized(0)).toEqual([['=A2']]) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards (with a range)', () => { - const engine = HyperFormula.buildFromArray([[null, null, null], ['=SUM(A1:C1)']]) - engine.moveRows(0, 1, 1, 0) - engine.setCellContents(adr('A1'), '=SUM(A2:C2)') - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(A2:C2)']]) - }) -}) - -describe('Move rows - row ranges', () => { - it('should adjust relative references of dependent formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2:3)'], - ['1'], - ['2'] - ]) - - engine.moveRows(0, 1, 2, 4) - - const range = extractRowRange(engine, adr('A1')) - expect(range.start).toEqual(rowStart(3)) - expect(range.end).toEqual(rowEnd(4)) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should adjust relative dependencies of moved formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2:3)'], - ['1'], - ['2'] - ]) - - engine.moveRows(0, 0, 1, 3) - - const range = extractRowRange(engine, adr('A3')) - expect(range.start).toEqual(rowStart(1)) - expect(range.end).toEqual(rowEnd(2)) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('should return #CYCLE when moving formula onto referred range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2:3)'], - ['1'], - ['2'] - ]) - - engine.moveRows(0, 0, 1, 2) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellFormula(adr('A2'))).toEqual('=SUM(1:3)') - }) -}) - -describe('Move rows - column ranges', () => { - it('should not affect moved column range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B:C)', '1', '2'], - ]) - - engine.moveRows(0, 0, 1, 2) - - const range = extractColumnRange(engine, adr('A2')) - expect(range.start).toEqual(colStart('B')) - expect(range.end).toEqual(colEnd('C')) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('should not affect dependent column range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B:C)', '1', '2'], - [null, '3', '4'], - ]) - - engine.moveRows(0, 1, 1, 3) - - const range = extractColumnRange(engine, adr('A1')) - expect(range.start).toEqual(colStart('B')) - expect(range.end).toEqual(colEnd('C')) - expect(engine.getCellValue(adr('A1'))).toEqual(10) - }) -}) diff --git a/test/unit/cruds/removing-columns.spec.ts b/test/unit/cruds/removing-columns.spec.ts deleted file mode 100644 index fb278786e5..0000000000 --- a/test/unit/cruds/removing-columns.spec.ts +++ /dev/null @@ -1,1020 +0,0 @@ -import {AlwaysDense, AlwaysSparse, ExportedCellChange, HyperFormula} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {ArrayFormulaVertex, RangeVertex} from '../../../src/DependencyGraph' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import {CellAddress} from '../../../src/parser' -import { - adr, - expectArrayWithSameContent, - expectEngineToBeTheSameAs, - expectFunctionToHaveRefError, - expectReferenceToHaveRefError, - extractMatrixRange, - extractRange, - extractReference, - noSpace, - verifyRangesInSheet, - verifyValues, -} from '../testUtils' - -describe('Removing columns - checking if its possible', () => { - it('no if starting column is negative', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveColumns(0, [-1, 1])).toEqual(false) - }) - - it('no if starting column is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveColumns(0, [1.5, 2])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(0, [NaN, 2])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(0, [Infinity, 2])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(0, [-Infinity, 2])).toEqual(false) - }) - - it('no if number of columns is negative', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveColumns(0, [0, -1])).toEqual(false) - }) - - it('no if number of columns is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveColumns(0, [0, 1.5])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(0, [0, NaN])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(0, [0, Infinity])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(0, [0, -Infinity])).toEqual(false) - }) - - it('no if sheet does not exist', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveColumns(1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(1.5, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(-1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(NaN, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(Infinity, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveColumns(-Infinity, [0, 1])).toEqual(false) - }) - - it('yes if theres an array in place where we remove', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=TRANSPOSE(A1:B2)'], - ['3', '4'], - ]) - - expect(engine.isItPossibleToRemoveColumns(0, [1, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveColumns(0, [1, 2])).toEqual(true) - expect(engine.isItPossibleToRemoveColumns(0, [2, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveColumns(0, [3, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveColumns(0, [4, 1])).toEqual(true) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveColumns(0, [0, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveColumns(0, [1, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveColumns(0, [1, 2])).toEqual(true) - }) -}) - -describe('Address dependencies, Case 1: same sheet', () => { - it('case Aa: absolute dependency before removed column should not be affected', () => { - const engine = HyperFormula.buildFromArray([ - ['', '1', '', '=$B1'], - ]) - - engine.removeColumns(0, [2, 1]) - - expect(extractReference(engine, adr('C1'))).toEqual(CellAddress.absoluteCol(1, 0)) - }) - - it('case Ab: absolute dependency after removed column should be shifted', () => { - const engine = HyperFormula.buildFromArray([ - ['=$C1', '', '42'], - ]) - - engine.removeColumns(0, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.absoluteCol(1, 0)) - }) - - it('case Ac: absolute dependency in removed column range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromArray([ - ['=$B1', ''], - ]) - - engine.removeColumns(0, [1, 1]) - - expectReferenceToHaveRefError(engine, adr('A1')) - }) - - it('case Raa: relative dependency and formula before removed columns should not be affected', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '=A1', '2'], - ]) - - engine.removeColumns(0, [2, 1]) - - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.relative(-1, 0)) - }) - - it('case Rab: relative address should be shifted when only formula is moving', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '1', '2', '=A1'], - ]) - - engine.removeColumns(0, [1, 2]) - - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.relative(-1, 0)) - }) - - it('case Rba: relative address should be shifted when only dependency is moving', () => { - const engine = HyperFormula.buildFromArray([ - ['=D1', '1', '2', '42'], - ]) - - engine.removeColumns(0, [1, 2]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(1, 0)) - }) - - it('case Rbb: relative address should not be affected when dependency and formula is moving', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=D1', '42'], - ]) - - engine.removeColumns(0, [0, 2]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(1, 0)) - }) - - it('case Rca: relative dependency in deleted column range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromArray([ - ['=C1', '1', '2', '3'], - ]) - - engine.removeColumns(0, [1, 2]) - - expectReferenceToHaveRefError(engine, adr('A1')) - }) - - it('case Rcb: relative dependency in deleted column range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=B1'], - ]) - - engine.removeColumns(0, [0, 2]) - - expectReferenceToHaveRefError(engine, adr('B1')) - }) - - it('case Rca, range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B1:C1)', '1', '2'], - ]) - - engine.removeColumns(0, [1, 2]) - - expectFunctionToHaveRefError(engine, adr('A1')) - }) - - it('truncates range by one column from left if first column removed', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A1:B1)'], - ]) - - engine.removeColumns(0, [0, 1]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('A1'))) - }) - - it('truncates range by one column from right if last column removed', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A1:B1)'], - ]) - - engine.removeColumns(0, [1, 1]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('A1'))) - }) - - it('truncates range by columns from left if leftmost columns removed', () => { - const engine = HyperFormula.buildFromArray([ - ['', '1', '2', '3', '4'], - ['=SUM(B1:E1)'], - ]) - - engine.removeColumns(0, [1, 2]) - - expect(extractRange(engine, adr('A2'))).toEqual(new AbsoluteCellRange(adr('B1'), adr('C1'))) - }) - - it('truncates range by columns from left if leftmost columns removed - removing does not have to start with range', () => { - const engine = HyperFormula.buildFromArray([ - ['', '', '1', '2', '3', '4'], - ['=SUM(C1:F1)'], - ]) - - engine.removeColumns(0, [1, 3]) - - expect(extractRange(engine, adr('A2'))).toEqual(new AbsoluteCellRange(adr('B1'), adr('C1'))) - }) - - it('truncates range by columns from left if leftmost columns removed - removing does not have to start with range but may end on start', () => { - const engine = HyperFormula.buildFromArray([ - ['', '', '1', '2', '3', '4'], - ['=SUM(C1:F1)'], - ]) - - engine.removeColumns(0, [1, 2]) - - expect(extractRange(engine, adr('A2'))).toEqual(new AbsoluteCellRange(adr('B1'), adr('D1'))) - }) - - it('truncates range by columns from right if rightmost columns removed', () => { - const engine = HyperFormula.buildFromArray([ - ['', '1', '2', '3', '4'], - ['=SUM(B1:E1)'], - ]) - - engine.removeColumns(0, [3, 2]) - - expect(extractRange(engine, adr('A2'))).toEqual(new AbsoluteCellRange(adr('B1'), adr('C1'))) - }) - - it('truncates range by columns from right if rightmost columns removed - removing does not have to end with range', () => { - const engine = HyperFormula.buildFromArray([ - ['', '1', '2', '3', '4', ''], - ['=SUM(B1:E1)'], - ]) - - engine.removeColumns(0, [3, 3]) - - expect(extractRange(engine, adr('A2'))).toEqual(new AbsoluteCellRange(adr('B1'), adr('C1'))) - }) - - it('truncates range by columns from right if rightmost columns removed - removing does not have to end with range but may start on end', () => { - const engine = HyperFormula.buildFromArray([ - ['', '1', '2', '3', '4', ''], - ['=SUM(B1:E1)'], - ]) - - engine.removeColumns(0, [4, 2]) - - expect(extractRange(engine, adr('A2'))).toEqual(new AbsoluteCellRange(adr('B1'), adr('D1'))) - }) -}) - -describe('Address dependencies, Case 2: formula in sheet where we make crud with dependency to other sheet', () => { - it('case A: should not affect absolute dependencies', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '=Sheet2!$A1'], - ], - Sheet2: [ - ['2'], - ], - }) - - engine.removeColumns(0, [0, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.absoluteCol(0, 0, 1)) - }) - - it('case Ra: removing column before formula should shift dependency', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '=Sheet2!A1'], - ], - Sheet2: [ - ['2'], - ], - }) - - engine.removeColumns(0, [0, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - }) - - it('case Rb: removing column after formula should not affect dependency', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1', '1'], - ], - Sheet2: [ - ['2'], - ], - }) - - engine.removeColumns(0, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - }) -}) - -describe('Address dependencies, Case 3: formula in different sheet', () => { - it('case ARa: relative/absolute dependency after removed column should be shifted', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!C1', '=Sheet2!C1', '=Sheet2!C1', '=Sheet2!$C1'], - ], - Sheet2: [ - ['1', '2', '3'], - ], - }) - - engine.removeColumns(1, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(1, 0, 1)) - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.relative(0, 0, 1)) - expect(extractReference(engine, adr('C1'))).toEqual(CellAddress.relative(-1, 0, 1)) - expect(extractReference(engine, adr('D1'))).toEqual(CellAddress.absoluteCol(1, 0, 1)) - }) - - it('case ARb: relative/absolute dependency before removed column should not be affected', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1', '=Sheet2!$A1'], - ], - Sheet2: [ - ['0', '1'], - ], - }) - - engine.removeColumns(1, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - expect(extractReference(engine, adr('B1'))).toEqual(CellAddress.absoluteCol(0, 0, 1)) - }) - - it('case ARc: relative/absolute dependency in removed range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!$A1', '=Sheet2!A1'], - ], - Sheet2: [ - ['1', '2'], - ], - }) - - engine.removeColumns(1, [0, 1]) - - expectReferenceToHaveRefError(engine, adr('A1')) - expectReferenceToHaveRefError(engine, adr('B1')) - }) - - it('does not truncate any ranges if columns are removed from different sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['', '2', '3'], - ['=SUM(B1:C1)'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.removeColumns(1, [1, 1]) - - expect(extractRange(engine, adr('A2'))).toEqual(new AbsoluteCellRange(adr('B1'), adr('C1'))) - }) -}) - -describe('Address dependencies, Case 4: remove columns in sheet different than formula or dependency sheet', () => { - it('should not affect dependency when removing columns in not relevant sheet', function() { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], - ], - Sheet2: [ - ['1', '=A1'], - ], - }) - - engine.removeColumns(0, [0, 1]) - - expect(extractReference(engine, adr('B1', 1))).toEqual(CellAddress.relative(-1, 0)) - }) - - it('should not affect dependency when removing columns in not relevant sheet, more sheets', function() { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], - ], - Sheet2: [ - ['foo'], - ], - Sheet3: [ - ['1', '=Sheet2!A1'], - ], - }) - - engine.removeColumns(0, [0, 1]) - - expect(extractReference(engine, adr('B1', 2))).toEqual(CellAddress.relative(-1, 0, 1)) - }) -}) - -describe('Removing columns - reevaluation', () => { - it('reevaluates', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(B1:D1)', '2', '4', '3'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - - engine.removeColumns(0, [2, 1]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2.5) - }) - - it('dont reevaluate everything', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '', '3'], - ['=COUNTBLANK(A1:C1)'], - ['=SUM(A1:A1)'], - ]) - const a2 = engine.addressMapping.getCell(adr('A2')) - const a3 = engine.addressMapping.getCell(adr('A3')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const a2setCellValueSpy = spyOn(a2 as any, 'setCellValue') - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const a3setCellValueSpy = spyOn(a3 as any, 'setCellValue') - - engine.removeColumns(0, [1, 1]) - - expect(a2setCellValueSpy).toHaveBeenCalled() - expect(a3setCellValueSpy).not.toHaveBeenCalled() - }) - - it('reevaluates cells which are dependent on structure changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=COLUMNS(A1:C1)'], - ]) - const d1 = engine.addressMapping.getCell(adr('D1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const d1setCellValueSpy = spyOn(d1 as any, 'setCellValue') - - engine.removeColumns(0, [1, 1]) - - expect(d1setCellValueSpy).toHaveBeenCalled() - expect(extractRange(engine, adr('C1'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B1'))) - }) - - it('should reevaluate formula when range reduced to zero', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A1:B1)'], - ]) - - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - - engine.removeColumns(0, [0, 2]) - - expect(c1setCellValueSpy).toHaveBeenCalled() - expectFunctionToHaveRefError(engine, adr('A1')) - }) - - it('returns changed values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A1:B1)'], - ]) - - const changes = engine.removeColumns(0, [0, 1]) - - expect(changes.length).toBe(1) - expect(changes).toEqual([new ExportedCellChange(adr('B1'), 2)]) - }) -}) - -describe('Removing rows - arrays', () => { - it('ArrayFormulaVertex#formula should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=TRANSPOSE(A1:C2)'], - ['4', '5', '6'], - ]) - - engine.removeColumns(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('C1'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B2'))) - }) - - it('ArrayFormulaVertex#address should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=TRANSPOSE(A1:C2)'], - ['4', '5', '6'], - ]) - - engine.removeColumns(0, [1, 1]) - - const matrixVertex = engine.addressMapping.getCell(adr('C1')) as ArrayFormulaVertex - expect(matrixVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('C1')) - }) - - it('ArrayFormulaVertex#formula should be updated when different sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2', '3'], - ['4', '5', '6'], - ], - Sheet2: [ - ['=TRANSPOSE(Sheet1!A1:C2)'], - ], - }) - - engine.removeColumns(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B2'))) - }) - - it('should be possible to remove column before array', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=-B3:D4', null, null, 'foo'], - ], {useArrayArithmetic: true}) - - engine.removeColumns(0, [0, 1]) - - const expected = HyperFormula.buildFromArray([ - ['=-A3:C4', null, null, 'foo'], - ], {useArrayArithmetic: true}) - - expectEngineToBeTheSameAs(engine, expected) - }) - - it('removing column across array should not change array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C2', null, null, null, 'foo'], - [4, 5, 6] - ], {useArrayArithmetic: true}) - - engine.removeColumns(0, [4, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2, 3, '=-A1:C2', null, null, 'foo'], - [4, 5, 6] - ], {useArrayArithmetic: true})) - }) - - it('removing column should shrink dependent array', () => { - const engine = HyperFormula.buildFromArray([ - [1, null, 3, '=TRANSPOSE(A1:C2)'], - [2, null, 4], - ], {useArrayArithmetic: true}) - - engine.removeColumns(0, [1, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 3, '=TRANSPOSE(A1:B2)'], - [2, 4], - ], {useArrayArithmetic: true})) - }) - - it('should be REF if no space after removing column', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C2:D2', null, 1], - [null, null, 1, 2] - ], {useArrayArithmetic: true}) - - engine.removeColumns(0, [1, 1]) - - expect(engine.getSheetValues(0)).toEqual([ - [noSpace(), 1], - [null, 1, 2], - ]) - - const expected = HyperFormula.buildFromArray([ - ['=-B2:C2', 1], - [null, 1, 2] - ], {useArrayArithmetic: true}) - - expectEngineToBeTheSameAs(engine, expected) - }) - - it('should be REF, not CYCLE, after removing columns', () => { - const engine = HyperFormula.buildFromArray([ - ['=-C1:D1', null, 1, 2] - ], {useArrayArithmetic: true}) - - engine.removeColumns(0, [1, 1]) - - expect(engine.getSheetValues(0)).toEqual([ - [noSpace(), 1, 2], - ]) - - const expected = HyperFormula.buildFromArray([ - ['=-B1:C1', 1, 2], - ], {useArrayArithmetic: true}) - expectEngineToBeTheSameAs(engine, expected) - }) - - it('should remove array when removing column with left corner', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=MMULT(A1:B2, A1:B2)'], - ['3', '4'], - ]) - - engine.removeColumns(0, [2, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4] - ])) - }) - - it('should remove array when removing columns with whole matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=MMULT(A1:B2, A1:B2)'], - ['3', '4'], - ]) - - engine.removeColumns(0, [2, 2]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4] - ])) - }) -}) - -describe('Removing columns - graph', function() { - it('should remove edges from other cells to removed nodes', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=B1'], - ]) - - engine.removeColumns(0, [2, 1]) - - const b1 = engine.addressMapping.getCell(adr('b1')) - expect(engine.graph.adjacentNodes(b1!)).toEqual(new Set()) - }) - - it('should remove vertices from graph', function() { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4'], - ['1', '2', '3', '4'], - ]) - expect(engine.graph.getNodes().length).toBe(8) - engine.removeColumns(0, [0, 2]) - expect(engine.graph.getNodes().length).toBe(4) // left two vertices in first column, two in last - }) - - it('works if there are empty cells removed', function() { - const engine = HyperFormula.buildFromArray([ - ['1', null, '3'], - ]) - expect(engine.graph.getNodes().length).toBe(2) - engine.removeColumns(0, [1, 1]) - expect(engine.graph.getNodes().length).toBe(2) - }) -}) - -describe('Removing columns - dependencies', () => { - it('should not affect absolute dependencies to other sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2', '=Sheet2!$A1'], - /* */ - ], - Sheet2: [ - ['3'], - ['4'], - ], - }) - - expect(extractReference(engine, adr('C1'))).toEqual(CellAddress.absoluteCol(0, 0, 1)) - engine.removeColumns(0, [0, 2]) - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.absoluteCol(0, 0, 1)) - }) - -}) - -describe('Removing columns - ranges', function() { - it('shift ranges in range mapping, range start at right of removed columns', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['', '=SUM(B1:C1)', ''], - /**/ - ]) - - engine.removeColumns(0, [0, 1]) - - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('B1')) - const a1 = engine.addressMapping.getCell(adr('A1')) - expect(engine.graph.existsEdge(a1!, range)).toBe(true) - }) - - it('shift ranges in range mapping, range start before removed columns', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['=SUM(A1:C1)', '', ''], - /* */ - ]) - - engine.removeColumns(0, [1, 2]) - - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A1')) - const a1 = engine.addressMapping.getCell(adr('A1')) - expect(engine.graph.existsEdge(a1!, range)).toBe(true) - }) - - it('shift ranges in range mapping, whole range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=SUM(A1:C1)'], - /* */ - ]) - const range = engine.rangeMapping.getRangeVertex(adr('A1'), adr('C1')) as RangeVertex - - engine.removeColumns(0, [0, 3]) - - const ranges = Array.from(engine.rangeMapping.rangesInSheet(0)) - expect(ranges.length).toBe(0) - expect(engine.graph.hasNode(range)).toBe(false) - }) - - it('does not truncate any ranges if columns are removed from different sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2', '=SUM(A1:B1)'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.removeColumns(1, [0, 1]) - - expect(extractRange(engine, adr('C1'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B1'))) - }) -}) - -describe('Removing columns - sheet dimensions', () => { - it('should do nothing when removing column outside effective sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const recalcSpy = spyOn(engine.evaluator as any, 'partialRun') - engine.removeColumns(0, [1, 1]) - engine.removeColumns(0, [10, 6]) - - expect(recalcSpy).not.toHaveBeenCalled() - expect(engine.getSheetDimensions(0)).toEqual({ - width: 1, - height: 1, - }) - }) - - it('should throw error when trying to remove non positive number of columns', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ]) - - expect(() => engine.removeColumns(0, [1, 0])).toThrowError() - }) -}) - -describe('Removing columns - column index', () => { - it('should update column index when adding column', () => { - const engine = HyperFormula.buildFromArray([ - ['', '1', '=VLOOKUP(2, A1:A10, 1, TRUE())'], - ], {useColumnIndex: true}) - - engine.removeColumns(0, [0, 1]) - - const index = (engine.columnSearch as ColumnIndex) - expectArrayWithSameContent([0], index.getValueIndex(0, 0, 1).index) - }) -}) - -describe('Removing columns - column range', () => { - it('removing column in the middle of column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=SUM(A:C)'] - ]) - - engine.removeColumns(0, [1, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '3', '=SUM(A:B)'] - ])) - }) - - it('removing column in at the start of column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=SUM(A:C)'] - ]) - - engine.removeColumns(0, [0, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['2', '3', '=SUM(A:B)'] - ])) - }) - - it('removing column in at the end of column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=SUM(A:C)'] - ]) - - engine.removeColumns(0, [2, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A:B)'] - ])) - }) -}) - -describe('Removing columns - row range', () => { - it('should not affect row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '1'], - ['2', '2', '2'], - [null, null, '=SUM(1:2)'] - ]) - - engine.removeColumns(0, [0, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '1'], - ['2', '2'], - [null, '=SUM(1:2)'] - ])) - }) -}) - -describe('Removing columns - merge ranges', () => { - it('should merge ranges', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 1, row: 2}, 7) - engine.setCellContents({sheet: 0, col: 0, row: 3}, '=SUM(B2:C3)') - engine.setCellContents({sheet: 0, col: 0, row: 6}, '=SUM(A4:B6)') - engine.setCellContents({sheet: 0, col: 2, row: 6}, '=SUM(A4:A6)') - - verifyRangesInSheet(engine, 0, ['A4:A6', 'A4:B6', 'B2:C3']) - verifyValues(engine) - - engine.addColumns(0, [0, 2]) - - verifyRangesInSheet(engine, 0, ['C4:C6', 'C4:D6', 'D2:E3']) - verifyValues(engine) - - engine.removeColumns(0, [3, 1]) - - verifyRangesInSheet(engine, 0, ['C4:C6', 'D2:D3']) - verifyValues(engine) - }) - - it('Should properly deallocate all nodes', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 2, row: 3}, '=SUM(B2:C2)') - engine.setCellContents({sheet: 0, col: 3, row: 5}, '=SUM(B2:C3)') - - engine.addColumns(0, [2, 2]) - engine.removeColumns(0, [4, 1]) - - verifyRangesInSheet(engine, 0, ['B2:D2', 'B2:D3']) - verifyValues(engine) - - engine.setCellContents({sheet: 0, col: 4, row: 5}, null) - - verifyRangesInSheet(engine, 0, []) - verifyValues(engine) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should merge ranges in proper order', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 0, row: 0}, '=SUM(D5:F5)') - engine.setCellContents({sheet: 0, col: 1, row: 0}, '=SUM(D5:E5)') - engine.setCellContents({sheet: 0, col: 2, row: 0}, '=SUM(D5:D5)') - - engine.removeColumns(0, [4, 1]) - - verifyRangesInSheet(engine, 0, ['D5:E5', 'D5:D5']) - verifyValues(engine) - - engine.setCellContents(adr('A1'), null) - engine.setCellContents(adr('B1'), null) - engine.setCellContents(adr('C1'), null) - - verifyRangesInSheet(engine, 0, []) - verifyValues(engine) - }) - - it('should merge ranges when removing multiple columns', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 3, row: 0}, '=SUM(A5:A5)') - engine.setCellContents({sheet: 0, col: 0, row: 0}, '=SUM(A5:C5)') - - verifyRangesInSheet(engine, 0, ['A5:A5', 'A5:C5']) - - engine.removeColumns(0, [1, 2]) - - verifyRangesInSheet(engine, 0, ['A5:A5']) - verifyValues(engine) - - engine.setCellContents(adr('A1'), null) - engine.setCellContents(adr('B1'), null) - - verifyRangesInSheet(engine, 0, []) - verifyValues(engine) - }) - - it('should undo merge ranges', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 2, row: 1}, 7) - engine.setCellContents({sheet: 0, col: 3, row: 0}, '=SUM(B2:C3)') - engine.setCellContents({sheet: 0, col: 6, row: 0}, '=SUM(A4:B6)') - engine.setCellContents({sheet: 0, col: 6, row: 2}, '=SUM(A4:A6)') - - engine.addColumns(0, [0, 2]) - engine.removeColumns(0, [3, 1]) - - verifyRangesInSheet(engine, 0, ['C4:C6', 'D2:D3']) - verifyValues(engine) - - engine.undo() - - verifyRangesInSheet(engine, 0, ['C4:C6', 'C4:D6', 'D2:E3']) - - verifyValues(engine) - }) -}) - -describe('Removing columns - changes', () => { - it('returns the same changes regardless of address mapping policy', () => { - const data = [ - [1, 2, '=A2'], - [3, 4, '=B1'], - ] - - const alwaysDenseEngine = HyperFormula.buildFromArray(data, { chooseAddressMappingPolicy: new AlwaysDense() }) - const alwaysDenseChanges = alwaysDenseEngine.removeColumns(0, [0, 2]) - const alwaysSparseEngine = HyperFormula.buildFromArray(data, { chooseAddressMappingPolicy: new AlwaysSparse() }) - const alwaysSparseChanges = alwaysSparseEngine.removeColumns(0, [0, 2]) - - expect(alwaysDenseChanges).toEqual(alwaysSparseChanges) - }) -}) - -describe('Removing column where there are empty rows in the address mapping (DenseStrategy) - issue #1406', () => { - it('should not throw errors (stackblitz reproduction)', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: 'gpl-v3', - chooseAddressMappingPolicy: new AlwaysDense() - }) - - const sheetName = hf.addSheet('main') - const sheetId = hf.getSheetId(sheetName)! - - hf.setCellContents( - { row: 0, col: 0, sheet: sheetId }, - [ - ['test', null, undefined, 4], - [null, 3, '=ISBLANK(B1)'], - ] - ) - - hf.addRows(0, [2, 1]) - hf.addRows(0, [3, 1]) - hf.setCellContents( - { row: 3, col: 0, sheet: sheetId }, - 'will-it-break?' - ) - hf.removeColumns(0, [0, 1]) //one column removed - - expect(hf.getSheetSerialized(0)).toEqual([ - [null, null, 4], - [3, '=ISBLANK(A1)'], - ]) - }) - - it('should not throw errors (user reported case)', () => { - const data= [ - [], - [null, 1], - [null, 2], - [null, '=sum(B2:B3)'] - ] - - const options = { licenseKey: 'gpl-v3', chooseAddressMappingPolicy: new AlwaysDense() } - const hf=HyperFormula.buildEmpty(options) - - hf.addSheet('sheet1') - hf.setSheetContent(0, data) - hf.removeColumns(0, [0, 1]) - - expect(hf.getSheetSerialized(0)).toEqual([ - [], - [1], - [2], - ['=SUM(A2:A3)'] - ]) - }) -}) diff --git a/test/unit/cruds/removing-rows.spec.ts b/test/unit/cruds/removing-rows.spec.ts deleted file mode 100644 index cf02c8b7df..0000000000 --- a/test/unit/cruds/removing-rows.spec.ts +++ /dev/null @@ -1,1131 +0,0 @@ -import {ExportedCellChange, HyperFormula, InvalidArgumentsError} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {ArrayFormulaVertex} from '../../../src/DependencyGraph' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import {CellAddress} from '../../../src/parser' -import { - adr, - expectArrayWithSameContent, - expectEngineToBeTheSameAs, - expectFunctionToHaveRefError, - expectReferenceToHaveRefError, - extractMatrixRange, - extractRange, - extractReference, graphReversedAdjacentNodes, - noSpace, - verifyRangesInSheet, - verifyValues, -} from '../testUtils' - -describe('Removing rows - checking if its possible', () => { - it('no if starting row is negative', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveRows(0, [-1, 1])).toEqual(false) - }) - - it('no if starting row is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveRows(0, [1.5, 2])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(0, [NaN, 2])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(0, [Infinity, 2])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(0, [-Infinity, 2])).toEqual(false) - }) - - it('no if number of rows is negative', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveRows(0, [0, -1])).toEqual(false) - }) - - it('no if number of rows is not an integer', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveRows(0, [0, 1.5])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(0, [0, NaN])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(0, [0, Infinity])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(0, [0, -Infinity])).toEqual(false) - }) - - it('no if sheet does not exist', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveRows(1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(1.5, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(-1, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(NaN, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(Infinity, [0, 1])).toEqual(false) - expect(engine.isItPossibleToRemoveRows(-Infinity, [0, 1])).toEqual(false) - }) - - it('yes if theres an array in place where we remove', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=TRANSPOSE(A1:B2)'], - ]) - - expect(engine.isItPossibleToRemoveRows(0, [1, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveRows(0, [1, 2])).toEqual(true) - expect(engine.isItPossibleToRemoveRows(0, [2, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveRows(0, [3, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveRows(0, [4, 1])).toEqual(true) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveRows(0, [0, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveRows(0, [1, 1])).toEqual(true) - expect(engine.isItPossibleToRemoveRows(0, [1, 2])).toEqual(true) - }) -}) - -describe('Address dependencies, Case 1: same sheet', () => { - it('case Aa: absolute dependency above removed row should not be affected', () => { - const engine = HyperFormula.buildFromArray([ - [null], - ['1'], - [null], // row to delete - ['=A$2'], - ]) - - engine.removeRows(0, [2, 1]) - - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.absoluteRow(0, 1)) - }) - - it('case Ab: absolute dependency below removed row should be shifted', () => { - const engine = HyperFormula.buildFromArray([ - ['=A$3'], - [null], // row to delete - ['42'], - ]) - - engine.removeRows(0, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.absoluteRow(0, 1)) - }) - - it('case Ac: absolute dependency in removed row range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromArray([ - ['=A$2'], - [null], // row to delete - ]) - - engine.removeRows(0, [1, 1]) - - expectReferenceToHaveRefError(engine, adr('A1')) - }) - - it('case Raa: relative dependency and formula above removed rows should not be affected', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['=A1'], - ['2'], - ]) - - engine.removeRows(0, [2, 1]) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.relative(0, -1)) - }) - - it('case Rab: relative address should be shifted when only formula is moving', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['1'], - ['2'], - ['=A1'], - ]) - - engine.removeRows(0, [1, 2]) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.relative(0, -1)) - }) - - it('case Rba: relative address should be shifted when only dependency is moving', () => { - const engine = HyperFormula.buildFromArray([ - ['=A4'], - ['1'], - ['2'], - ['42'], - ]) - - engine.removeRows(0, [1, 2]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 1)) - }) - - it('case Rbb: relative address should not be affected when dependency and formula is moving', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=A4'], - ['42'], - ]) - - engine.removeRows(0, [0, 2]) - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 1)) - }) - - it('case Rca: relative dependency in deleted row range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromArray([ - ['=A3'], - ['1'], - ['2'], - ['3'], - ]) - - engine.removeRows(0, [1, 2]) - expectReferenceToHaveRefError(engine, adr('A1')) - }) - - it('case Rcb: relative dependency in deleted row range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['=A2'], - ]) - - engine.removeRows(0, [0, 2]) - expectReferenceToHaveRefError(engine, adr('A2')) - }) - - it('case Rca, range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(A2:A3)'], - ['1'], // - ['2'], // - ]) - engine.removeRows(0, [1, 2]) - expectFunctionToHaveRefError(engine, adr('A1')) - }) -}) - -describe('Address dependencies, Case 2: formula in sheet where we make crud with dependency to other sheet', () => { - it('case A: should not affect absolute dependencies', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], // row to delete - ['=Sheet2!A$1'], - ], - Sheet2: [ - ['2'], - ], - }) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.absoluteRow(0, 0, 1)) - engine.removeRows(0, [0, 1]) - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.absoluteRow(0, 0, 1)) - }) - - it('case Ra: removing row above formula should shift dependency', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], // row to delete - ['=Sheet2!A1'], - ], - Sheet2: [ - ['2'], - ], - }) - - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.relative(0, -1, 1)) - engine.removeRows(0, [0, 1]) - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - }) - - it('case Rb: removing row below formula should not affect dependency', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1'], - ['1'], // row to delete - ], - Sheet2: [ - ['2'], - ], - }) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - engine.removeRows(0, [1, 1]) - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - }) -}) - -describe('Address dependencies, Case 3: formula in different sheet', () => { - it('case ARa: relative/absolute dependency below removed row should be shifted', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A3'], - ['=Sheet2!A3'], - ['=Sheet2!A3'], - ['=Sheet2!A$3'], - ], - Sheet2: [ - ['1'], - ['2'], // row to delete - ['3'], - ], - }) - - engine.removeRows(1, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 1, 1)) - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.relative(0, 0, 1)) - expect(extractReference(engine, adr('A3'))).toEqual(CellAddress.relative(0, -1, 1)) - expect(extractReference(engine, adr('A4'))).toEqual(CellAddress.absoluteRow(0, 1, 1)) - }) - - it('case ARb: relative/absolute dependency above removed row should not be affected', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1'], - ['=Sheet2!A$1'], - ], - Sheet2: [ - ['0'], - ['1'], // row to delete - ], - }) - - engine.removeRows(1, [1, 1]) - - expect(extractReference(engine, adr('A1'))).toEqual(CellAddress.relative(0, 0, 1)) - expect(extractReference(engine, adr('A2'))).toEqual(CellAddress.absoluteRow(0, 0, 1)) - }) - - it('case ARc: relative/absolute dependency in removed range should be replaced by #REF', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A$1'], - ['=Sheet2!A1'], - ], - Sheet2: [ - ['1'], // row to delete - ['2'], - ], - }) - - engine.removeRows(1, [0, 1]) - - expectReferenceToHaveRefError(engine, adr('A1')) - expectReferenceToHaveRefError(engine, adr('A2')) - }) - - it('does not truncate any ranges if rows are removed from different sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - [null, '=SUM(A2:A3)'], - ['2'], - ['3'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.removeRows(1, [1, 1]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A3'))) - }) -}) - -describe('Address dependencies, Case 4: remove rows in sheet different than formula or dependency sheet', () => { - it('should not affect dependency when removing rows in not relevant sheet', function() { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], // to remove - ], - Sheet2: [ - ['1'], - ['=A1'], - ], - }) - - engine.removeRows(0, [0, 1]) - - expect(extractReference(engine, adr('A2', 1))).toEqual(CellAddress.relative(0, -1)) - }) - - it('should not affect dependency when removing rows in not relevant sheet, more sheets', function() { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], // to remove - ], - Sheet2: [ - ['foo'], - ], - Sheet3: [ - ['1'], - ['=Sheet2!A1'], - ], - }) - - engine.removeRows(0, [0, 1]) - - expect(extractReference(engine, adr('A2', 2))).toEqual(CellAddress.relative(0, -1, 1)) - }) -}) - -describe('Removing rows - range dependencies, same sheet', () => { - it('truncates range by one row from top if topmost row removed', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A2:A3)'], - ['1'], - ['2'], - ]) - - engine.removeRows(0, [1, 1]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A2'))) - }) - - it('truncates range by one row from bottom if last row removed', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A2:A3)'], - ['1'], - ['2'], - ]) - - engine.removeRows(0, [2, 1]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A2'))) - }) - - it('truncates range by rows from top if topmost rows removed', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A2:A5)'], - ['2'], - ['3'], - ['4'], - ['5'], - ]) - - engine.removeRows(0, [1, 2]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A3'))) - }) - - it('truncates range by rows from top if topmost rows removed - removing does not have to start with range', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A3:A6)'], - [null], - ['3'], - ['4'], - ['5'], - ['6'], - ]) - - engine.removeRows(0, [1, 3]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A3'))) - }) - - it('truncates range by rows from top if topmost rows removed - removing does not have to start with range but may end on start', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A3:A6)'], - [null], - ['3'], - ['4'], - ['5'], - ['6'], - ]) - - engine.removeRows(0, [1, 2]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A4'))) - }) - - it('truncates range by rows from bottom if bottomest rows removed', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A2:A5)'], - ['2'], - ['3'], - ['4'], - ['5'], - ]) - - engine.removeRows(0, [3, 2]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A3'))) - }) - - it('truncates range by rows from bottom if bottomest rows removed - removing does not have to end with range', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A2:A5)'], - ['2'], - ['3'], - ['4'], - ['5'], - [null], - ]) - - engine.removeRows(0, [3, 3]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A3'))) - }) - - it('truncates range by rows from bottom if bottomest rows removed - removing does not have to end with range but may start on end', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=SUM(A2:A5)'], - ['2'], - ['3'], - ['4'], - ['5'], - [null], - ]) - - engine.removeRows(0, [4, 2]) - - expect(extractRange(engine, adr('B1'))).toEqual(new AbsoluteCellRange(adr('A2'), adr('A4'))) - }) -}) - -describe('Removing rows - reevaluation', () => { - it('reevaluates cells', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=COUNTBLANK(A1:A3)'], - [null], // deleted - ['3'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(1) - engine.removeRows(0, [1, 1]) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('dont reevaluate everything', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=COUNTBLANK(A1:A3)', '=SUM(A1:A1)'], - [null], // deleted - ['3'], - ]) - const b1 = engine.addressMapping.getCell(adr('B1')) - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const b1setCellValueSpy = spyOn(b1 as any, 'setCellValue') - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - - engine.removeRows(0, [1, 1]) - - expect(b1setCellValueSpy).toHaveBeenCalled() - expect(c1setCellValueSpy).not.toHaveBeenCalled() - }) - - it('reevaluates cells which are dependent on structure changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=COLUMNS(A1:B1)'], - ['1'], - ]) - const c1 = engine.addressMapping.getCell(adr('C1')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const c1setCellValueSpy = spyOn(c1 as any, 'setCellValue') - - engine.removeRows(0, [1, 1]) - - expect(c1setCellValueSpy).toHaveBeenCalled() - }) - - it('should reevaluate formula when range reduced to zero', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=SUM(A1:A2)'], - ]) - - const a3 = engine.addressMapping.getCell(adr('A3')) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const a3setCellValueSpy = spyOn(a3 as any, 'setCellValue') - - engine.removeRows(0, [0, 2]) - - expect(a3setCellValueSpy).toHaveBeenCalled() - expectFunctionToHaveRefError(engine, adr('A1')) - }) -}) - -describe('Removing rows - arrays', () => { - it('ArrayFormulaVertex#formula should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '4'], - ['2', '5'], - ['3', '6'], - ['=TRANSPOSE(A1:B3)'], - ]) - - engine.removeRows(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('A3'))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B2'))) - }) - - it('ArrayFormulaVertex#address should be updated', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '4'], - ['2', '5'], - ['3', '6'], - ['=TRANSPOSE(A1:B3)'], - ]) - - engine.removeRows(0, [1, 1]) - - const matrixVertex = engine.addressMapping.getCell(adr('A3')) as ArrayFormulaVertex - expect(matrixVertex.getAddress(engine.lazilyTransformingAstService)).toEqual(adr('A3')) - }) - - it('ArrayFormulaVertex#formula should be updated when different sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '4'], - ['2', '5'], - ['3', '6'], - ], - Sheet2: [ - ['=TRANSPOSE(Sheet1!A1:B3)'], - ], - }) - - engine.removeRows(0, [1, 1]) - - expect(extractMatrixRange(engine, adr('A1', 1))).toEqual(new AbsoluteCellRange(adr('A1'), adr('B2'))) - }) - - it('should be possible to remove row above array', () => { - const engine = HyperFormula.buildFromArray([ - [], - ['=-C2:D4'], - [], - [], - ['foo'] - ], {useArrayArithmetic: true}) - - engine.removeRows(0, [0, 1]) - - const expected = HyperFormula.buildFromArray([ - ['=-C1:D3'], - [], - [], - ['foo'] - ], {useArrayArithmetic: true}) - - expectEngineToBeTheSameAs(engine, expected) - }) - - it('removing row across array should not change array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], [3, 4], [5, 6], - ['=-A1:B3'], - [], [], [], - ['foo'] - ], {useArrayArithmetic: true}) - - engine.removeRows(0, [4, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], [3, 4], [5, 6], - ['=-A1:B3'], - [], [], - ['foo'] - ], {useArrayArithmetic: true})) - }) - - it('removing row should shrink dependent array', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [], - [3, 4], - ['=TRANSPOSE(A1:B3)'] - ], {useArrayArithmetic: true}) - - engine.removeRows(0, [1, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ['=TRANSPOSE(A1:B2)'] - ], {useArrayArithmetic: true})) - }) - - it('should be REF if no space after removing row', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B3:B4'], - [], - [1, 1], - [null, 2], - ], {useArrayArithmetic: true}) - - engine.removeRows(0, [1, 1]) - - expect(engine.getSheetValues(0)).toEqual([ - [noSpace()], - [1, 1], - [null, 2], - ]) - - const expected = HyperFormula.buildFromArray([ - ['=-B2:B3'], - [1, 1], - [null, 2] - ], {useArrayArithmetic: true}) - expectEngineToBeTheSameAs(engine, expected) - }) - - it('should be REF, not CYCLE, after removing rows', () => { - const engine = HyperFormula.buildFromArray([ - ['=-A3:A4'], - [], - [1], - [2] - ], {useArrayArithmetic: true}) - - engine.removeRows(0, [1, 1]) - - expect(engine.getSheetValues(0)).toEqual([ - [noSpace()], - [1], - [2] - ]) - - const expected = HyperFormula.buildFromArray([ - ['=-A2:A3'], - [1], - [2] - ], {useArrayArithmetic: true}) - expectEngineToBeTheSameAs(engine, expected) - }) - - it('should remove array when removing row with left corner', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=MMULT(A1:B2, A1:B2)'], - ]) - - engine.removeRows(0, [2, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4] - ])) - }) - - it('should remove array when removing rows with whole matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=MMULT(A1:B2, A1:B2)'], - ]) - - engine.removeRows(0, [2, 2]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - [1, 2], - [3, 4] - ])) - }) -}) - -describe('Removing rows - graph', function() { - it('should remove edges from other cells to removed nodes', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=A2'], // - ]) - - engine.removeRows(0, [2, 1]) - - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(engine.graph.adjacentNodes(a2!)).toEqual(new Set()) - }) - - it('should remove vertices from graph', function() { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ]) - expect(engine.graph.getNodes().length).toBe(4) - engine.removeRows(0, [0, 2]) - expect(engine.graph.getNodes().length).toBe(0) - }) - - it('works if there are empty cells removed', function() { - const engine = HyperFormula.buildFromArray([ - ['1'], - [null], - ['3'], - ]) - expect(engine.graph.getNodes().length).toBe(2) - engine.removeRows(0, [1, 1]) - expect(engine.graph.getNodes().length).toBe(2) - }) -}) - -describe('Removing rows - range mapping', function() { - it('shift ranges in range mapping, range start below removed rows', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null], - ['2', '=SUM(A2:A3)'], - ['3', null], - ]) - - engine.removeRows(0, [0, 1]) - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) - const a1 = engine.addressMapping.getCell(adr('A1')) - expect(engine.graph.existsEdge(a1!, range)).toBe(true) - }) - - it('shift ranges in range mapping, range start above removed rows', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(A1:A3)'], - ['2', null], - ['3', null], - ]) - - engine.removeRows(0, [1, 2]) - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A1')) - const a1 = engine.addressMapping.getCell(adr('A1')) - expect(engine.graph.existsEdge(a1!, range)).toBe(true) - }) - - it('shift ranges in range mapping, whole range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['=SUM(A1:A3)'], - ]) - - const range = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) - engine.removeRows(0, [0, 3]) - const ranges = Array.from(engine.rangeMapping.rangesInSheet(0)) - expect(ranges.length).toBe(0) - expect(engine.graph.hasNode(range)).toBe(false) - }) - - it('should remove smaller range dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['=SUM(A1:A2)'], - ['=SUM(A1:A3)'], - ]) - - const a1a3 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) - expect(graphReversedAdjacentNodes(engine.graph, a1a3).length).toBe(2) - engine.removeRows(0, [0, 2]) - const a1a1 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A1')) - expect(a1a1).toBe(a1a3) - expect(graphReversedAdjacentNodes(engine.graph, a1a1).length).toBe(1) - }) -}) - -describe('Removing rows - sheet dimensions', () => { - it('should do nothing when removed row outside effective sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const recalcSpy = spyOn(engine.evaluator as any, 'partialRun') - engine.removeRows(0, [1, 1]) - engine.removeRows(0, [10, 6]) - - expect(recalcSpy).not.toHaveBeenCalled() - expect(engine.getSheetDimensions(0)).toEqual({ - width: 1, - height: 1, - }) - }) - - it('should throw error when trying to remove non positive number of rows', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ]) - - expect(() => engine.removeRows(0, [1, 0])).toThrow(new InvalidArgumentsError('starting row to be smaller than the ending row.')) - }) - - it('returns changed values', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=SUM(A1:A2)'], - ]) - - const changes = engine.removeRows(0, [0, 1]) - - expect(changes.length).toBe(1) - expect(changes).toContainEqual(new ExportedCellChange(adr('A2'), 2)) - }) -}) - -describe('Removing rows - column index', () => { - it('should update column index when adding row', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=VLOOKUP(2, A1:A10, 1, TRUE())'], - [null], - ['2'], - ], {useColumnIndex: true}) - - engine.removeRows(0, [1, 1]) - - const index = (engine.columnSearch as ColumnIndex) - - expectArrayWithSameContent([0], index.getValueIndex(0, 0, 1).index) - expectArrayWithSameContent([1], index.getValueIndex(0, 0, 2).index) - }) -}) - -describe('Removing rows - row range', () => { - it('removing rows - start of row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ['1', '2'], - ['=SUM(1:3)'] - ]) - - engine.removeRows(0, [0, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ['=SUM(1:2)'] - ])) - }) - - it('removing rows - middle of row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ['1', '2'], - ['=SUM(1:3)'] - ]) - - engine.removeRows(0, [1, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ['=SUM(1:2)'] - ])) - }) - - it('removing rows - end of row range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ['1', '2'], - ['=SUM(1:3)'] - ]) - - engine.removeRows(0, [2, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ['=SUM(1:2)'] - ])) - }) -}) - -describe('Removing rows - column range', () => { - it('should not affect column range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ['1', '2', '=SUM(A:B)'], - ]) - - engine.removeRows(0, [0, 1]) - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2', '=SUM(A:B)'], - ])) - }) -}) - -describe('Removing rows - merge ranges', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 4, row: 0}, '=SUM(A1:C1)') - engine.setCellContents({sheet: 0, col: 3, row: 1}, '=SUM(A1:C2)') - engine.setCellContents({sheet: 0, col: 4, row: 0}, '=SUM(A1:C2)') - - verifyRangesInSheet(engine, 0, ['A1:C1', 'A1:C2']) - - engine.addRows(0, [1, 2]) - engine.removeRows(0, [3, 1]) - - verifyRangesInSheet(engine, 0, ['A1:C1', 'A1:C2', 'A1:C3']) - - engine.setCellContents({sheet: 0, col: 4, row: 0}, '=SUM(B2:B3)') - engine.addRows(0, [1, 2]) - - verifyRangesInSheet(engine, 0, ['B4:B5']) - }) - - it('should not remove too much', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 3, row: 0}, '=SUM(A1:C2)') - engine.setCellContents({sheet: 0, col: 4, row: 0}, '=SUM(A1:C1)') - - verifyRangesInSheet(engine, 0, ['A1:C1', 'A1:C2']) - - engine.addRows(0, [0, 2]) - engine.removeRows(0, [3, 1]) - - verifyRangesInSheet(engine, 0, ['A3:C3']) - verifyValues(engine) - - engine.setCellContents({sheet: 0, col: 3, row: 2}, '=SUM(A2:B3)') - engine.setCellContents({sheet: 0, col: 4, row: 2}, '=SUM(A2:B3)') - - verifyRangesInSheet(engine, 0, ['A2:B3']) - verifyValues(engine) - }) - - it('should merge ranges', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 2, row: 1}, 7) - engine.setCellContents({sheet: 0, col: 3, row: 0}, '=SUM(B2:C3)') - engine.setCellContents({sheet: 0, col: 6, row: 0}, '=SUM(D1:F2)') - engine.setCellContents({sheet: 0, col: 6, row: 2}, '=SUM(D1:F1)') - - verifyRangesInSheet(engine, 0, ['D1:F1', 'D1:F2', 'B2:C3']) - verifyValues(engine) - - engine.addRows(0, [0, 2]) - - verifyRangesInSheet(engine, 0, ['D3:F3', 'D3:F4', 'B4:C5']) - verifyValues(engine) - - engine.removeRows(0, [3, 1]) - - verifyRangesInSheet(engine, 0, ['D3:F3', 'B4:C4']) - verifyValues(engine) - }) - - it('Should properly deallocate all nodes', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 3, row: 2}, '=SUM(B2:C2)') - engine.setCellContents({sheet: 0, col: 5, row: 3}, '=SUM(B2:C3)') - - engine.addRows(0, [2, 2]) - engine.removeRows(0, [4, 1]) - - verifyRangesInSheet(engine, 0, ['B2:C2', 'B2:C3', 'B2:C4']) - verifyValues(engine) - - engine.setCellContents({sheet: 0, col: 5, row: 4}, null) - - verifyRangesInSheet(engine, 0, []) - verifyValues(engine) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should merge ranges in proper order', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 0, row: 0}, '=SUM(A4:A6)') - engine.setCellContents({sheet: 0, col: 0, row: 1}, '=SUM(A4:A5)') - engine.setCellContents({sheet: 0, col: 0, row: 2}, '=SUM(A4:A4)') - - engine.removeRows(0, [4, 1]) - - verifyRangesInSheet(engine, 0, ['A4:A5', 'A4:A4']) - verifyValues(engine) - - engine.setCellContents(adr('A1'), null) - engine.setCellContents(adr('A2'), null) - engine.setCellContents(adr('A3'), null) - - verifyRangesInSheet(engine, 0, []) - verifyValues(engine) - }) - - it('should merge ranges with subranges in proper order', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 0, row: 1}, '=SUM(E1:E1)') - engine.setCellContents({sheet: 0, col: 0, row: 0}, '=SUM(E1:E2)') - - engine.addRows(0, [1, 2]) - - verifyRangesInSheet(engine, 0, ['E1:E1', 'E1:E2', 'E1:E3', 'E1:E4']) - verifyValues(engine) - - engine.removeRows(0, [2, 1]) - - verifyRangesInSheet(engine, 0, ['E1:E1', 'E1:E2', 'E1:E3']) - verifyValues(engine) - - engine.setCellContents(adr('A1'), null) - engine.setCellContents(adr('A3'), null) - - verifyRangesInSheet(engine, 0, []) - verifyValues(engine) - }) - - it('should merge ranges when removing multiple rows', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 0, row: 3}, '=SUM(E1:E1)') - engine.setCellContents({sheet: 0, col: 0, row: 0}, '=SUM(E1:E3)') - - verifyRangesInSheet(engine, 0, ['E1:E1', 'E1:E3']) - - engine.removeRows(0, [1, 2]) - - verifyRangesInSheet(engine, 0, ['E1:E1']) - verifyValues(engine) - - engine.setCellContents(adr('A1'), null) - engine.setCellContents(adr('A2'), null) - - verifyRangesInSheet(engine, 0, []) - verifyValues(engine) - }) - - it('should merge ranges when removing multiple rows 2', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 0, row: 3}, '=SUM(E1:E1)') - engine.setCellContents({sheet: 0, col: 0, row: 2}, '=SUM(E1:E2)') - - engine.addRows(0, [1, 2]) - - verifyRangesInSheet(engine, 0, ['E1:E1', 'E1:E2', 'E1:E3', 'E1:E4']) - - engine.setCellContents({sheet: 0, col: 0, row: 5}, '=SUM(E4:E4)') - - verifyRangesInSheet(engine, 0, ['E1:E1', 'E1:E2', 'E1:E3', 'E1:E4', 'E4:E4']) - - engine.removeRows(0, [1, 3]) - - verifyRangesInSheet(engine, 0, ['E1:E1']) - verifyValues(engine) - }) - - it('should undo merge ranges', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents({sheet: 0, col: 2, row: 1}, 7) - engine.setCellContents({sheet: 0, col: 3, row: 0}, '=SUM(B2:C3)') - engine.setCellContents({sheet: 0, col: 6, row: 0}, '=SUM(D1:F2)') - engine.setCellContents({sheet: 0, col: 6, row: 2}, '=SUM(D1:F1)') - - engine.addRows(0, [0, 2]) - engine.removeRows(0, [3, 1]) - - verifyRangesInSheet(engine, 0, ['D3:F3', 'B4:C4']) - verifyValues(engine) - - engine.undo() - - verifyRangesInSheet(engine, 0, ['D3:F3', 'D3:F4', 'B4:C5']) - verifyValues(engine) - }) -}) diff --git a/test/unit/cruds/removing-sheet.spec.ts b/test/unit/cruds/removing-sheet.spec.ts deleted file mode 100644 index 08c39c4ee2..0000000000 --- a/test/unit/cruds/removing-sheet.spec.ts +++ /dev/null @@ -1,860 +0,0 @@ -import {ExportedCellChange, HyperFormula, NoSheetWithIdError, CellValueType} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {ErrorType} from '../../../src/Cell' -import {ArrayFormulaVertex} from '../../../src/DependencyGraph' -import { ErrorMessage } from '../../../src/error-message' -import {ColumnIndex} from '../../../src/Lookup/ColumnIndex' -import {CellAddress} from '../../../src/parser' -import { - adr, - detailedError, - detailedErrorWithOrigin, - expectArrayWithSameContent, - extractReference, -} from '../testUtils' - -describe('Removing sheet - checking if its possible', () => { - it('no if theres no such sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveSheet(1)).toBe(false) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToRemoveSheet(0)).toBe(true) - }) -}) - -describe('remove sheet', () => { - it('should throw error when trying to remove not existing sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(() => { - engine.removeSheet(1) - }).toThrow(new NoSheetWithIdError(1)) - }) - - it('should remove sheet by id', () => { - const engine = HyperFormula.buildFromArray([['foo']]) - - engine.removeSheet(0) - - expect(engine.sheetMapping.numberOfSheets()).toBe(0) - expect(Array.from(engine.addressMapping.entries())).toEqual([]) - }) - - it('should remove empty sheet', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.removeSheet(0) - - expect(engine.sheetMapping.numberOfSheets()).toBe(0) - expect(Array.from(engine.addressMapping.entries())).toEqual([]) - }) - - it('should remove sheet with matrix', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1'], - ['{=TRANSPOSE(A1:A1)}'], - ], - }) - - engine.removeSheet(0) - - expect(engine.sheetMapping.numberOfSheets()).toBe(0) - expect(Array.from(engine.addressMapping.entries())).toEqual([]) - }) - - it('should remove sheet with formula matrix', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['{=TRANSPOSE(A1:B1)}'], - ['{=TRANSPOSE(A1:B1)}'], - ], - }) - - engine.removeSheet(0) - - expect(engine.sheetMapping.numberOfSheets()).toBe(0) - expect(Array.from(engine.addressMapping.entries())).toEqual([]) - }) - - it('should remove a sheet with a cell reference to a value in the same sheet', () => { - const engine = HyperFormula.buildFromArray([ - [1, '=A1'], - ]) - - engine.removeSheet(0) - - expect(engine.sheetMapping.numberOfSheets()).toBe(0) - expect(Array.from(engine.addressMapping.entries())).toEqual([]) - }) - - it('should not affect data in the sheets that were referenced by the sheet being removed', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1)'], - ['=SUM(Sheet2!A1:A2)'], - ], - Sheet2: [ - [1], - [2], - [3], - ], - }) - - engine.removeSheet(0) - - expect(Array.from(engine.sheetMapping.iterateSheetNames())).toEqual(['Sheet2']) - expect(engine.getCellValue(adr('A1', 1))).toBe(1) - expect(engine.getCellValue(adr('A2', 1))).toBe(2) - expect(engine.getCellValue(adr('A3', 1))).toBe(3) - }) - - it('converts sheet to placeholder if other sheet depends on it', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [[42]], - Sheet2: [['=Sheet1!A1']], - }) - - const sheet1Id = engine.getSheetId('Sheet1')! - - engine.removeSheet(sheet1Id) - - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: false })).toBe(false) - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: true })).toBe(true) - }) - - it('removes sheet completely if nothing depends on it', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [[42]], - Sheet2: [[100]], - }) - - const sheet1Id = engine.getSheetId('Sheet1')! - - engine.removeSheet(sheet1Id) - - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: false })).toBe(false) - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: true })).toBe(false) - }) - - it('removes the placeholder sheet if nothing depends on it any longer', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [[42]], - Sheet2: [['=Sheet1!A1']], - }) - - const sheet1Id = engine.getSheetId('Sheet1')! - const sheet2Id = engine.getSheetId('Sheet2')! - - engine.removeSheet(sheet1Id) - - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: false })).toBe(false) - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: true })).toBe(true) - - engine.setCellContents(adr('A1', sheet2Id), 100) - - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: false })).toBe(false) - expect(engine.sheetMapping.hasSheetWithId(sheet1Id, { includePlaceholders: true })).toBe(false) - }) - - it('decreases lastSheetId if removed sheet was the last one', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [[1]], - Sheet2: [[2]], - }) - - const sheet2Id = engine.getSheetId('Sheet2')! - - engine.removeSheet(sheet2Id) - - engine.addSheet('Sheet3') - const sheet3Id = engine.getSheetId('Sheet3')! - - expect(sheet3Id).toBe(sheet2Id) // new sheet reuses the ID - }) -}) - -describe('remove sheet - adjust edges', () => { - it('should not affect dependencies to sheet other than removed', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '=A1'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.removeSheet(1) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - - expect(engine.graph.existsEdge(a1!, b1!)).toBe(true) - }) - - it('should remove edge between sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1'], - ], - Sheet2: [ - ['1'], - ], - }) - - const a1From0 = engine.addressMapping.getCell(adr('A1')) - const a1From1 = engine.addressMapping.getCell(adr('A1', 1)) - - expect(engine.graph.existsEdge(a1From1!, a1From0!)).toBe(true) - - engine.removeSheet(1) - - expect(engine.graph.existsEdge(a1From1!, a1From0!)).toBe(false) - }) -}) - -describe('remove sheet - adjust formula dependencies', () => { - it('should not affect formula with dependency to sheet other than removed', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '=A1'], - ], - Sheet2: [ - ['1'], - ], - }) - - engine.removeSheet(1) - - const reference = extractReference(engine, adr('B1')) - - expect(reference).toEqual(CellAddress.relative(-1, 0)) - expect(engine.getAllSheetsSerialized()).toEqual({Sheet1: [['1', '=A1']]}) - expect(engine.getAllSheetsValues()).toEqual({Sheet1: [[1, 1]]}) - }) - - it('should be #REF after removing sheet', () => { - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [ - ['=Sheet2!A1'], - ['=Sheet2!A1:A2'], - ['=Sheet2!A:B'], - ['=Sheet2!1:2'], - ], - [sheet2Name]: [ - ['1'], - ], - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - const sheet2Id = engine.getSheetId(sheet2Name)! - - engine.removeSheet(sheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A3', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A4', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return changed values', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=Sheet2!A1'], - ], - Sheet2: [ - ['1'], - ], - }) - - const changes = engine.removeSheet(1) - - expect(changes.length).toBe(1) - expect(changes).toContainEqual(new ExportedCellChange(adr('A1'), detailedErrorWithOrigin(ErrorType.REF, 'Sheet1!A1', ErrorMessage.SheetRef))) - }) - -}) - -describe('removeSheet() recalculates formulas (issue #1116)', () => { - it('returns REF error if other sheet depends on the removed one', () => { - const table1Name = 'table1' - const table2Name = 'table2' - const engine = HyperFormula.buildFromSheets({ - [table1Name]: [[`='${table2Name}'!A1`]], - [table2Name]: [[10]], - }) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(table1Name)))).toBe(10) - expect(engine.getCellValue(adr('A1', engine.getSheetId(table2Name)))).toBe(10) - - engine.removeSheet(engine.getSheetId(table2Name)!) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(table1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', engine.getSheetId(table2Name)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('returns REF error for chained dependencies across multiple sheets', () => { - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - const sheet3Name = 'Sheet3' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[`='${sheet2Name}'!A1+2`]], - [sheet2Name]: [[`='${sheet3Name}'!A1*2`]], - [sheet3Name]: [[42]], - }) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toBe(84) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(86) - - engine.removeSheet(engine.getSheetId(sheet3Name)!) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('returns REF error for nested dependencies within same sheet referencing removed sheet', () => { - const sheet1Name = 'Sheet1' - const removedSheetName = 'RemovedSheet' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [['=B1*2', `='${removedSheetName}'!A1`]], - [removedSheetName]: [[15]], - }) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toBe(15) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(30) - - engine.removeSheet(engine.getSheetId(removedSheetName)!) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('returns REF error for multiple cells from different sheets referencing removed sheet', () => { - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - const targetSheetName = 'TargetSheet' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[`='${targetSheetName}'!A1`, `='${targetSheetName}'!B1`]], - [sheet2Name]: [[`='${targetSheetName}'!A1+10`, `='${targetSheetName}'!B1+20`]], - [targetSheetName]: [[5, 7]], - }) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(5) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toBe(7) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toBe(15) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet2Name)))).toBe(27) - - engine.removeSheet(engine.getSheetId(targetSheetName)!) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet2Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet2Name)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('returns REF error for formulas with mixed operations combining removed sheet references', () => { - const sheet1Name = 'Sheet1' - const removedSheetName = 'RemovedSheet' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[100, `='${removedSheetName}'!A1 + A1`, `='${removedSheetName}'!B1 * 2`]], - [removedSheetName]: [[50, 25]], - }) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toBe(150) - expect(engine.getCellValue(adr('C1', engine.getSheetId(sheet1Name)))).toBe(50) - - engine.removeSheet(engine.getSheetId(removedSheetName)!) - - expect(engine.getCellValue(adr('B1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('returns REF error for formulas with multi-cell ranges from removed sheet', () => { - const sheet1Name = 'Sheet1' - const dataSheetName = 'DataSheet' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [ - [`=SUM('${dataSheetName}'!A1:B5)`], - [`=MEDIAN('${dataSheetName}'!A1:B5)`], - ], - [dataSheetName]: [ - [1, 2], - [3, 4], - [5, 6], - [7, 8], - [9, 10], - ], - }) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(55) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toBe(5.5) - - engine.removeSheet(engine.getSheetId(dataSheetName)!) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('returns REF error for named expressions referencing removed sheet', () => { - const sheet1Name = 'Sheet1' - const removedSheetName = 'RemovedSheet' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [['=MyValue'], ['=MyValue*2']], - [removedSheetName]: [[99]] - }, {}, [ - { name: 'MyValue', expression: `='${removedSheetName}'!$A$1` } - ]) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toBe(99) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toBe(198) - - engine.removeSheet(engine.getSheetId(removedSheetName)!) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', engine.getSheetId(sheet1Name)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('handles add-remove-add cycle correctly', () => { - const engine = HyperFormula.buildEmpty() - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - - engine.addSheet(sheet1Name) - const sheet1Id = engine.getSheetId(sheet1Name)! - engine.setCellContents(adr('A1', sheet1Id), `='${sheet2Name}'!A1`) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(sheet2Name) - const oldSheet2Id = engine.getSheetId(sheet2Name)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBeNull() - - engine.setCellContents(adr('A1', oldSheet2Id), 42) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('A1', oldSheet2Id))).toBe(42) - - engine.removeSheet(oldSheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', oldSheet2Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(sheet2Name) - let newSheet2Id = engine.getSheetId(sheet2Name)! - engine.setCellContents(adr('A1', newSheet2Id), 43) - - expect(newSheet2Id).toBe(oldSheet2Id) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(43) - expect(engine.getCellValue(adr('A1', newSheet2Id))).toBe(43) - - engine.removeSheet(oldSheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', oldSheet2Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(sheet2Name) - newSheet2Id = engine.getSheetId(sheet2Name)! - engine.setCellContents(adr('A1', newSheet2Id), 44) - - expect(newSheet2Id).toBe(oldSheet2Id) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(44) - expect(engine.getCellValue(adr('A1', newSheet2Id))).toBe(44) - - engine.removeSheet(oldSheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', oldSheet2Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet(sheet2Name) - newSheet2Id = engine.getSheetId(sheet2Name)! - engine.setCellContents(adr('A1', newSheet2Id), 45) - - expect(newSheet2Id).toBe(oldSheet2Id) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(45) - expect(engine.getCellValue(adr('A1', newSheet2Id))).toBe(45) - }) - - it('REF error propagates through dependency chain when source sheet is removed', () => { - const engine = HyperFormula.buildFromSheets({ - 'Main': [['=Intermediate!A1*2']], - 'Intermediate': [['=Source!A1+10']], - 'Source': [[5]], - }) - const mainId = engine.getSheetId('Main')! - const intermediateId = engine.getSheetId('Intermediate')! - const sourceId = engine.getSheetId('Source')! - - expect(engine.getCellValue(adr('A1', mainId))).toBe(30) - expect(engine.getCellValue(adr('A1', intermediateId))).toBe(15) - - // Remove source sheet - error should propagate through chain - engine.removeSheet(sourceId) - - expect(engine.getCellValue(adr('A1', intermediateId))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - // Re-add the sheet to resolve the errors - engine.addSheet('Source') - engine.setCellContents(adr('A1', engine.getSheetId('Source')), 5) - - expect(engine.getCellValue(adr('A1', intermediateId))).toBe(15) - expect(engine.getCellValue(adr('A1', mainId))).toBe(30) - }) - - it('removing sheet creates REF and adding it back resolves it', () => { - const engine = HyperFormula.buildFromSheets({ - 'Main': [['=Data!A1']], - 'Data': [[42]], - }) - const mainId = engine.getSheetId('Main')! - const dataId = engine.getSheetId('Data')! - - expect(engine.getCellValue(adr('A1', mainId))).toBe(42) - - engine.removeSheet(dataId) - - expect(engine.getCellValue(adr('A1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - engine.addSheet('Data') - engine.setCellContents(adr('A1', engine.getSheetId('Data')), 99) - - expect(engine.getCellValue(adr('A1', mainId))).toBe(99) - }) - - describe('when using ranges with', () => { - it('function using `runFunction`', () => { - const sheet1Name = 'FirstSheet' - const sheet2Name = 'NewSheet' - const sheet1Data = [['=MEDIAN(NewSheet!A1:A1)', '=MEDIAN(NewSheet!A1:A2)', '=MEDIAN(NewSheet!A1:A3)', '=MEDIAN(NewSheet!A1:A4)']] - const sheet2Data = [[1], [2], [3], [4]] - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: sheet1Data, - [sheet2Name]: sheet2Data, - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - const sheet2Id = engine.getSheetId(sheet2Name)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(1.5) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(2.5) - - engine.removeSheet(sheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('function not using `runFunction`', () => { - const sheet1Name = 'FirstSheet' - const sheet2Name = 'NewSheet' - const sheet1Data = [['=SUM(NewSheet!A1:A1)', '=SUM(NewSheet!A1:A2)', '=SUM(NewSheet!A1:A3)', '=SUM(NewSheet!A1:A4)']] - const sheet2Data = [[1], [2], [3], [4]] - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: sheet1Data, - [sheet2Name]: sheet2Data, - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - const sheet2Id = engine.getSheetId(sheet2Name)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(3) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(6) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(10) - - engine.removeSheet(sheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('function using `runFunction` referencing range indirectly', () => { - const sheet1Name = 'FirstSheet' - const sheet2Name = 'NewSheet' - const sheet1Data = [ - ['=MEDIAN(A2)', '=MEDIAN(B2)', '=MEDIAN(C2)', '=MEDIAN(D2)'], - [`='${sheet2Name}'!A1:A1`, `='${sheet2Name}'!A1:B2`, `='${sheet2Name}'!A1:A3`, `='${sheet2Name}'!A1:A4`], - ] - const sheet2Data = [[1], [2], [3], [4]] - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: sheet1Data, - [sheet2Name]: sheet2Data, - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - const sheet2Id = engine.getSheetId(sheet2Name)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(1.5) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(2.5) - - engine.removeSheet(sheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('function not using `runFunction` referencing range indirectly', () => { - const sheet1Name = 'FirstSheet' - const sheet2Name = 'NewSheet' - const sheet1Data = [ - ['=SUM(A2)', '=SUM(B2)', '=SUM(C2)', '=SUM(D2)'], - [`='${sheet2Name}'!A1:A1`, `='${sheet2Name}'!A1:B2`, `='${sheet2Name}'!A1:A3`, `='${sheet2Name}'!A1:A4`], - ] - const sheet2Data = [[1], [2], [3], [4]] - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: sheet1Data, - [sheet2Name]: sheet2Data, - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - const sheet2Id = engine.getSheetId(sheet2Name)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(3) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(6) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(10) - - engine.removeSheet(sheet2Id) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('function calling a named expression', () => { - const sheet1Name = 'FirstSheet' - const sheet2Name = 'NewSheet' - const sheet1Data = [[`='${sheet2Name}'!A1:A4`]] - const sheet2Data = [[1], [2], [3], [4]] - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: sheet1Data, - [sheet2Name]: sheet2Data, - }, {}, [ - { name: 'ExprA', expression: `=MEDIAN(${sheet2Name}!$A$1:$A$1)` }, - { name: 'ExprB', expression: `=MEDIAN(${sheet2Name}!$A$1:$A$2)` }, - { name: 'ExprC', expression: `=MEDIAN(${sheet2Name}!$A$1:$A$3)` }, - { name: 'ExprD', expression: `=MEDIAN(${sheet1Name}!$A$1)` } - ]) - - const sheet2Id = engine.getSheetId(sheet2Name)! - - expect(engine.getNamedExpressionValue('ExprA')).toBe(1) - expect(engine.getNamedExpressionValue('ExprB')).toBe(1.5) - expect(engine.getNamedExpressionValue('ExprC')).toBe(2) - expect(engine.getNamedExpressionValue('ExprD')).toBe(2.5) - - engine.removeSheet(sheet2Id) - - expect(engine.getNamedExpressionValue('ExprA')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprB')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprC')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprD')).toEqualError(detailedError(ErrorType.REF)) - }) - }) -}) - -describe('remove sheet - adjust address mapping', () => { - it('should remove sheet from address mapping if nothing depends on it', () => { - const sheet1Name = 'Sheet1' - - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[42]] - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - engine.removeSheet(sheet1Id) - - expect(() => engine.addressMapping.getStrategyForSheetOrThrow(sheet1Id)).toThrow(new NoSheetWithIdError(sheet1Id)) - }) - - it('should not remove sheet from address mapping if another sheet depends on it', () => { - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[42]], - [sheet2Name]: [[`='${sheet1Name}'!A1`]], - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - - engine.removeSheet(sheet1Id) - - expect(() => engine.addressMapping.getStrategyForSheetOrThrow(sheet1Id)).not.toThrow() - }) - - it('should not remove sheet from address mapping if a named expression depends on it', () => { - const sheet1Name = 'Sheet1' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[42]], - }, {}, [ - { name: 'namedExpressionName', expression: `='${sheet1Name}'!$A$1` }, - ]) - - const sheet1Id = engine.getSheetId(sheet1Name)! - - engine.removeSheet(sheet1Id) - - expect(() => engine.addressMapping.getStrategyForSheetOrThrow(sheet1Id)).not.toThrow() - }) - - it('removes the placeholder sheet from address mapping if nothing depends on it any longer', () => { - const sheet1Name = 'Sheet1' - const sheet2Name = 'Sheet2' - - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[42]], - [sheet2Name]: [[`='${sheet1Name}'!A1`]], - }) - - const sheet1Id = engine.getSheetId(sheet1Name)! - const sheet2Id = engine.getSheetId(sheet2Name)! - - engine.removeSheet(sheet1Id) - - expect(() => engine.addressMapping.getStrategyForSheetOrThrow(sheet1Id)).not.toThrow() - - engine.setCellContents(adr('A1', sheet2Id), 100) - - expect(() => engine.addressMapping.getStrategyForSheetOrThrow(sheet1Id)).toThrow(new NoSheetWithIdError(sheet1Id)) - }) -}) - -describe('remove sheet - adjust range mapping', () => { - it('should remove ranges from range mapping when removing sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=SUM(B1:B2)'], - ['=SUM(C1:C2)'], - ], - Sheet2: [ - ['=SUM(B1:B2)'], - ['=SUM(C1:C2)'], - ], - }) - - expect(Array.from(engine.rangeMapping.rangesInSheet(0)).length).toBe(2) - expect(Array.from(engine.rangeMapping.rangesInSheet(1)).length).toBe(2) - - engine.removeSheet(0) - - expect(Array.from(engine.rangeMapping.rangesInSheet(0)).length).toBe(0) - expect(Array.from(engine.rangeMapping.rangesInSheet(1)).length).toBe(2) - }) -}) - -describe('remove sheet - adjust matrix mapping', () => { - it('should remove matrices from matrix mapping when removing sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ], - Sheet2: [ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ], - }) - - expect(engine.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2))).toBeInstanceOf(ArrayFormulaVertex) - - engine.removeSheet(0) - - expect(engine.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2))).toBeUndefined() - expect(engine.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2', 1), 1, 2))).toBeInstanceOf(ArrayFormulaVertex) - }) -}) - -describe('remove sheet - adjust column index', () => { - it('should remove sheet from index', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ], {useColumnIndex: true}) - const index = engine.columnSearch as ColumnIndex - const removeSheetSpy = spyOn(index, 'removeSheet') - - engine.removeSheet(0) - - expect(removeSheetSpy).toHaveBeenCalledWith(0) - expectArrayWithSameContent([], index.getValueIndex(0, 0, 1).index) - }) -}) - -describe('remove sheet - placeholder sheet behavior', () => { - it('should return ERROR type when getting cell value from a placeholder sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [[42]], - Sheet2: [['=Sheet1!A1']], - }) - - const sheet1Id = engine.getSheetId('Sheet1')! - - engine.removeSheet(sheet1Id) - - expect(engine.getCellValueType(adr('A1', sheet1Id))).toBe('ERROR') - }) - - it('should return null when getting serialized cell from a placeholder sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [[42]], - Sheet2: [['=Sheet1!A1']], - }) - - const sheet1Id = engine.getSheetId('Sheet1')! - - engine.removeSheet(sheet1Id) - - const result = engine.getCellSerialized(adr('A1', sheet1Id)) - expect(result).toBeNull() - }) - - it('should remove range vertices when clearing formulas that use ranges', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=SUM(A1:C1)'], - ]) - - expect(engine.rangeMapping.getNumberOfRangesInSheet(0)).toBe(1) - - engine.setCellContents(adr('A2'), null) - - expect(engine.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should remove range vertices when removing sheet with ranges', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - [1, 2, 3], - ['=SUM(A1:C1)'], - ], - Sheet2: [[100]], - }) - - expect(engine.rangeMapping.getNumberOfRangesInSheet(0)).toBe(1) - - engine.removeSheet(0) - - expect(engine.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) -}) diff --git a/test/unit/cruds/rename-sheet.spec.ts b/test/unit/cruds/rename-sheet.spec.ts deleted file mode 100644 index 1114f63ff8..0000000000 --- a/test/unit/cruds/rename-sheet.spec.ts +++ /dev/null @@ -1,583 +0,0 @@ -import {HyperFormula, NoSheetWithIdError, SheetNameAlreadyTakenError} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {adr, detailedError} from '../testUtils' - -describe('isItPossibleToRenameSheet() returns', () => { - it('true if possible', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': []}) - - expect(engine.isItPossibleToRenameSheet(0, 'Foo')).toBe(true) - expect(engine.isItPossibleToRenameSheet(0, '~`!@#$%^&*()_-+_=/|?{}[]\"')).toBe(true) - }) - - it('true if same name', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': []}) - - expect(engine.isItPossibleToRenameSheet(0, 'Sheet1')).toBe(true) - }) - - it('false if sheet does not exists', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': []}) - - expect(engine.isItPossibleToRenameSheet(1, 'Foo')).toBe(false) - }) - - it('false if given name is taken', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [], 'Sheet2': []}) - - expect(engine.isItPossibleToRenameSheet(0, 'Sheet2')).toBe(false) - }) -}) - -describe('renameSheet()', () => { - it('renames sheet and updates sheet mapping', () => { - const engine = HyperFormula.buildEmpty() - engine.addSheet('foo') - - engine.renameSheet(0, 'bar') - - expect(engine.getSheetName(0)).toBe('bar') - expect(engine.doesSheetExist('foo')).toBe(false) - expect(engine.doesSheetExist('bar')).toBe(true) - }) - - it('throws error when sheet with given ID does not exist', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => { - engine.renameSheet(0, 'bar') - }).toThrow(new NoSheetWithIdError(0)) - }) - - it('throws error when new sheet name is already taken', () => { - const engine = HyperFormula.buildEmpty() - engine.addSheet() - engine.addSheet('bar') - - expect(() => { - engine.renameSheet(0, 'bar') - }).toThrow(new SheetNameAlreadyTakenError('bar')) - }) - - it('allows renaming to the same name (no-op)', () => { - const engine = HyperFormula.buildEmpty() - engine.addSheet('foo') - - engine.renameSheet(0, 'foo') - - expect(engine.getSheetName(0)).toBe('foo') - expect(engine.doesSheetExist('foo')).toBe(true) - }) - - it('allows changing case of the same canonical name', () => { - const engine = HyperFormula.buildEmpty() - engine.addSheet('Foo') - - engine.renameSheet(0, 'FOO') - - expect(engine.getSheetName(0)).toBe('FOO') - expect(engine.doesSheetExist('FOO')).toBe(true) - }) - - describe('recalculates formulas (issue #1116)', () => { - it('recalculates single cell reference', () => { - const sheet1Name = 'Sheet1' - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[`='${newName}'!A1`]], - [oldName]: [[42]], - }) - const sheet1Id = engine.getSheetId(sheet1Name)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - }) - - it('recalculates nested dependencies within same sheet', () => { - const sheet1Name = 'Sheet1' - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [['=B1*2', `='${newName}'!A1`]], - [oldName]: [[15]], - }) - const sheet1Id = engine.getSheetId(sheet1Name)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(15) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(30) - }) - - it('recalculates formulas with mixed operations', () => { - const sheet1Name = 'Sheet1' - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[100, `='${newName}'!A1 + A1`, `='${newName}'!B1 * 2`]], - [oldName]: [[50, 25]], - }) - const sheet1Id = engine.getSheetId(sheet1Name)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(150) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(50) - }) - - it('recalculates named expressions', () => { - const sheet1Name = 'Sheet1' - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [['=MyValue'], ['=MyValue*2']], - [oldName]: [[99]], - }, {}, [ - { name: 'MyValue', expression: `='${newName}'!$A$1` } - ]) - const sheet1Id = engine.getSheetId(sheet1Name)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(99) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(198) - }) - - it('moves reserved range vertices onto renamed sheet', () => { - const formulaSheet = 'FormulaSheet' - const oldName = 'SourceSheet' - const newName = 'GhostSheet' - const engine = HyperFormula.buildFromSheets({ - [formulaSheet]: [[`=SUM('${newName}'!A1:B1)`]], - [oldName]: [[1, 2]], - }) - const formulaSheetId = engine.getSheetId(formulaSheet)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', formulaSheetId))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - const renamedSheetId = engine.getSheetId(newName)! - - expect(engine.getCellValue(adr('A1', formulaSheetId))).toBe(3) - - const movedRange = engine.rangeMapping.getRangeVertex(adr('A1', renamedSheetId), adr('B1', renamedSheetId)) - - expect(movedRange).toBeDefined() - expect(movedRange?.sheet).toBe(renamedSheetId) - }) - - it('merges duplicate range vertices after renaming into reserved name', () => { - const oldName = 'OldName' - const newName = 'GhostSheet' - const usesOld = 'UsesOld' - const usesNew = 'UsesNew' - const engine = HyperFormula.buildFromSheets({ - [usesOld]: [[`=SUM('${oldName}'!A1:A2)`]], - [usesNew]: [[`=SUM('${newName}'!A1:A2)`]], - [oldName]: [[5], [7]], - }) - const usesOldId = engine.getSheetId(usesOld)! - const usesNewId = engine.getSheetId(usesNew)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', usesOldId))).toBe(12) - expect(engine.getCellValue(adr('A1', usesNewId))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getCellValue(adr('A1', usesOldId))).toBe(12) - expect(engine.getCellValue(adr('A1', usesNewId))).toBe(12) - expect(engine.getCellFormula(adr('A1', usesNewId))).toBe(`=SUM(${newName}!A1:A2)`) - expect(engine.getCellFormula(adr('A1', usesOldId))).toBe(`=SUM(${newName}!A1:A2)`) - - engine.setCellContents(adr('A1', oldNameId), 100) - - expect(engine.getCellValue(adr('A1', usesOldId))).toBe(107) - expect(engine.getCellValue(adr('A1', usesNewId))).toBe(107) - }) - - it('recalculates column and row ranges', () => { - const sheet1Name = 'Sheet1' - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [ - [`=SUM('${newName}'!A:A)`], - [`=SUM('${newName}'!1:2)`], - ], - [oldName]: [ - [1, 2], - [3, 4], - ], - }) - const sheet1Id = engine.getSheetId(sheet1Name)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(4) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(10) - }) - - it('keeps existing dependencies and dependents when renaming a sheet', () => { - const mainSheetName = 'Sheet1' - const secondarySheetName = 'Sheet2' - const newNameForSecondarySheet = 'Sheet3' - const engine = HyperFormula.buildFromSheets({ - [mainSheetName]: [['main sheet', `=${secondarySheetName}!A1`, `=${newNameForSecondarySheet}!A1`]], - [secondarySheetName]: [['secondary sheet', `=${mainSheetName}!A1`]], - }) - const mainSheetId = engine.getSheetId(mainSheetName)! - const secondarySheetId = engine.getSheetId(secondarySheetName)! - - expect(engine.getCellValue(adr('B1', mainSheetId))).toBe('secondary sheet') - expect(engine.getCellValue(adr('C1', mainSheetId))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', secondarySheetId))).toBe('main sheet') - - engine.renameSheet(secondarySheetId, newNameForSecondarySheet) - - expect(engine.getSheetId(newNameForSecondarySheet)).toBe(secondarySheetId) - expect(engine.getCellValue(adr('B1', mainSheetId))).toBe('secondary sheet') - expect(engine.getCellValue(adr('C1', mainSheetId))).toBe('secondary sheet') - expect(engine.getCellValue(adr('B1', secondarySheetId))).toBe('main sheet') - }) - - it('removing renamed sheet returns REF error', () => { - const sheet1Name = 'Sheet1' - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[`='${newName}'!A1`]], - [oldName]: [[42]], - }) - const sheet1Id = engine.getSheetId(sheet1Name)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getSheetId(newName)).toBe(oldNameId) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - - engine.removeSheet(oldNameId) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('adding sheet with the same name as new name of renamed sheet throws error', () => { - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [oldName]: [[42]], - }) - const oldNameId = engine.getSheetId(oldName)! - - engine.renameSheet(oldNameId, newName) - - expect(() => { - engine.addSheet(newName) - }).toThrow(new SheetNameAlreadyTakenError(newName)) - }) - - it('adding sheet with the old name of renamed sheet creates new sheet', () => { - const sheet1Name = 'Sheet1' - const oldName = 'OldName' - const newName = 'NewName' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[`='${oldName}'!A1`]], - [oldName]: [[42]], - }) - const sheet1Id = engine.getSheetId(sheet1Name)! - const oldNameId = engine.getSheetId(oldName)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - - engine.renameSheet(oldNameId, newName) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - - engine.addSheet(oldName) - engine.setCellContents(adr('A1', engine.getSheetId(oldName)), 100) - - expect(engine.getSheetId(oldName)).not.toBe(engine.getSheetId(newName)) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('A1', engine.getSheetId(newName)))).toBe(42) - expect(engine.getCellValue(adr('A1', engine.getSheetId(oldName)))).toBe(100) - }) - - - it('renaming sheet that references non-existent sheet keeps REF error', () => { - const sheet1Name = 'Sheet1' - const newName = 'NewName' - const nonExistent = 'NonExistent' - const engine = HyperFormula.buildFromSheets({ - [sheet1Name]: [[`='${nonExistent}'!A1`]], - }) - const sheet1Id = engine.getSheetId(sheet1Name)! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(sheet1Id, newName) - - expect(engine.getCellValue(adr('A1', engine.getSheetId(newName)))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('chain renaming resolves multiple placeholder references sequentially', () => { - const engine = HyperFormula.buildFromSheets({ - 'Main': [['=SheetB!A1', '=SheetC!A1']], - 'SheetA': [[10]], - }) - const mainId = engine.getSheetId('Main')! - const sheetAId = engine.getSheetId('SheetA')! - - // Both are initially REF errors (placeholders) - expect(engine.getCellValue(adr('A1', mainId))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - // Rename SheetA → SheetB: resolves first placeholder - engine.renameSheet(sheetAId, 'SheetB') - - expect(engine.getCellValue(adr('A1', mainId))).toBe(10) - expect(engine.getCellValue(adr('B1', mainId))).toEqualError(detailedError(ErrorType.REF)) - // Formula A1 now references SheetB (follows the rename) - expect(engine.getCellFormula(adr('A1', mainId))).toBe('=SheetB!A1') - - // Add a new sheet named SheetC to resolve second placeholder - engine.addSheet('SheetC') - engine.setCellContents(adr('A1', engine.getSheetId('SheetC')), 20) - - expect(engine.getCellValue(adr('A1', mainId))).toBe(10) - expect(engine.getCellValue(adr('B1', mainId))).toBe(20) - }) - - it('renaming sheet with circular formula does not break engine', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=Sheet2!A1']], - 'Sheet2': [['=Sheet1!A1']], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const sheet2Id = engine.getSheetId('Sheet2')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('A1', sheet2Id))).toEqualError(detailedError(ErrorType.CYCLE)) - - engine.renameSheet(sheet1Id, 'RenamedSheet1') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('A1', sheet2Id))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellFormula(adr('A1', sheet2Id))).toBe('=RenamedSheet1!A1') - }) - - it('multiple formulas referencing same placeholder all resolve after rename', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=Ghost!A1'], ['=Ghost!A1+1'], ['=SUM(Ghost!A1:A2)']], - 'Sheet2': [['=Ghost!A1*2'], ['=Ghost!B1']], - 'RealSheet': [[100, 200], [300]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const sheet2Id = engine.getSheetId('Sheet2')! - const realSheetId = engine.getSheetId('RealSheet')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A3', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', sheet2Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A2', sheet2Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(realSheetId, 'Ghost') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(101) - expect(engine.getCellValue(adr('A3', sheet1Id))).toBe(400) - expect(engine.getCellValue(adr('A1', sheet2Id))).toBe(200) - expect(engine.getCellValue(adr('A2', sheet2Id))).toBe(200) - }) - - it('when new name is already referenced, engine merges both sheet names', () => { - const engine = HyperFormula.buildFromSheets({ - 'Main': [['=Source!A1', '=Target!A1']], - 'Source': [[42]], - }) - const mainId = engine.getSheetId('Main')! - const sourceId = engine.getSheetId('Source')! - - expect(engine.getCellValue(adr('A1', mainId))).toBe(42) - expect(engine.getCellValue(adr('B1', mainId))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(sourceId, 'Target') - - expect(engine.getCellFormula(adr('A1', mainId))).toBe('=Target!A1') - expect(engine.getCellFormula(adr('B1', mainId))).toBe('=Target!A1') - expect(engine.getCellValue(adr('A1', mainId))).toBe(42) - expect(engine.getCellValue(adr('B1', mainId))).toBe(42) - - engine.setCellContents(adr('A1', sourceId), 100) - - expect(engine.getCellValue(adr('A1', mainId))).toBe(100) - expect(engine.getCellValue(adr('B1', mainId))).toBe(100) - }) - - it('handles deeply nested REF error propagation', () => { - const engine = HyperFormula.buildFromSheets({ - 'L1': [['=L2!A1+1']], - 'L2': [['=L3!A1+1']], - 'L3': [['=L4!A1+1']], - 'L4': [['=Ghost!A1']], - 'Source': [[100]], - }) - const l1Id = engine.getSheetId('L1')! - const l2Id = engine.getSheetId('L2')! - const l3Id = engine.getSheetId('L3')! - const l4Id = engine.getSheetId('L4')! - const sourceId = engine.getSheetId('Source')! - - expect(engine.getCellValue(adr('A1', l1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', l2Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', l3Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('A1', l4Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(sourceId, 'Ghost') - - expect(engine.getCellValue(adr('A1', l4Id))).toBe(100) - expect(engine.getCellValue(adr('A1', l3Id))).toBe(101) - expect(engine.getCellValue(adr('A1', l2Id))).toBe(102) - expect(engine.getCellValue(adr('A1', l1Id))).toBe(103) - }) - - describe('when using ranges with', () => { - it('function using `runFunction`', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [['=MEDIAN(NewName!A1:A1)', '=MEDIAN(NewName!A1:A2)', '=MEDIAN(NewName!A1:A3)', '=MEDIAN(NewName!A1:A4)']], - 'OldName': [[1], [2], [3], [4]], - }) - const sheet1Id = engine.getSheetId('FirstSheet')! - const sheet2Id = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(sheet2Id, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(1.5) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(2.5) - }) - - it('function not using `runFunction`', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [['=SUM(NewName!A1:A1)', '=SUM(NewName!A1:A2)', '=SUM(NewName!A1:A3)', '=SUM(NewName!A1:A4)']], - 'OldName': [[1], [2], [3], [4]], - }) - const sheet1Id = engine.getSheetId('FirstSheet')! - const sheet2Id = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(sheet2Id, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(3) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(6) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(10) - }) - - it('function using `runFunction` referencing range indirectly', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [ - ['=MEDIAN(A2)', '=MEDIAN(B2)', '=MEDIAN(C2)', '=MEDIAN(D2)'], - ['=\'NewName\'!A1:A1', '=\'NewName\'!A1:B2', '=\'NewName\'!A1:A3', '=\'NewName\'!A1:A4'], - ], - 'OldName': [[1], [2], [3], [4]], - }) - const sheet1Id = engine.getSheetId('FirstSheet')! - const sheet2Id = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(sheet2Id, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(1.5) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(2.5) - }) - - it('function not using `runFunction` referencing range indirectly', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [ - ['=SUM(A2)', '=SUM(B2)', '=SUM(C2)', '=SUM(D2)'], - ['=\'NewName\'!A1:A1', '=\'NewName\'!A1:B2', '=\'NewName\'!A1:A3', '=\'NewName\'!A1:A4'], - ], - 'OldName': [[1], [2], [3], [4]], - }) - const sheet1Id = engine.getSheetId('FirstSheet')! - const sheet2Id = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(sheet2Id, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(3) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(6) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(10) - }) - - it('function calling a named expression', () => { - const engine = HyperFormula.buildFromSheets({ - 'FirstSheet': [['=\'OldName\'!A1:A4']], - 'OldName': [[1], [2], [3], [4]], - }, {}, [ - { name: 'ExprA', expression: '=MEDIAN(NewName!$A$1:$A$1)' }, - { name: 'ExprB', expression: '=MEDIAN(NewName!$A$1:$A$2)' }, - { name: 'ExprC', expression: '=MEDIAN(NewName!$A$1:$A$3)' }, - ]) - - expect(engine.getNamedExpressionValue('ExprA')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprB')).toEqualError(detailedError(ErrorType.REF)) - expect(engine.getNamedExpressionValue('ExprC')).toEqualError(detailedError(ErrorType.REF)) - - engine.renameSheet(engine.getSheetId('OldName')!, 'NewName') - - expect(engine.getNamedExpressionValue('ExprA')).toBe(1) - expect(engine.getNamedExpressionValue('ExprB')).toBe(1.5) - expect(engine.getNamedExpressionValue('ExprC')).toBe(2) - }) - }) - }) -}) diff --git a/test/unit/cruds/replace-sheet-content.spec.ts b/test/unit/cruds/replace-sheet-content.spec.ts deleted file mode 100644 index f969b760ec..0000000000 --- a/test/unit/cruds/replace-sheet-content.spec.ts +++ /dev/null @@ -1,118 +0,0 @@ -import {ExportedCellChange, HyperFormula} from '../../../src' -import {adr, expectArrayWithSameContent} from '../testUtils' - -describe('Replace sheet content - checking if its possible', () => { - it('no if theres no such sheet', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToReplaceSheetContent(1, [])).toEqual(false) - }) - - it('yes otherwise', () => { - const engine = HyperFormula.buildFromArray([[]]) - - expect(engine.isItPossibleToReplaceSheetContent(0, [])).toEqual(true) - }) -}) - -describe('Replace sheet content', () => { - it('should throw error trying to replace not existing sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', 'foo'], - ]) - - expect(() => { - engine.setSheetContent(1, [['3', '4']]) - - }).toThrowError("There's no sheet with id = 1") - }) - - it('should replace sheet content with new values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', 'foo'], - ]) - - engine.setSheetContent(0, [['3', '4']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('A2'))).toBe(null) - expect(engine.getCellValue(adr('B2'))).toBe(null) - }) - - /* for now return only new values */ - it('should return changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', 'foo'], - ]) - - const changes = engine.setSheetContent(0, [['3', '4']]) - - expectArrayWithSameContent(changes, [ - new ExportedCellChange(adr('A1'), 3), - new ExportedCellChange(adr('B1'), 4), - ]) - }) - - /* should we return removed values? */ - xit('should return new values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', 'foo'], - ]) - - const changes = engine.setSheetContent(0, [['3', '4']]) - - expect(changes.length).toEqual(4) - - expectArrayWithSameContent(changes, [ - new ExportedCellChange(adr('A1'), 3), - new ExportedCellChange(adr('B1'), 4), - new ExportedCellChange(adr('A2'), null), - new ExportedCellChange(adr('B2'), null), - ]) - }) - - it('should replace content of a sheet with formula matrix', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['{=TRANSPOSE(A1:B1)}'], - ], - Sheet2: [ - ['=Sheet1!A2'], - ['=Sheet1!A3'], - ], - }) - - engine.setSheetContent(0, [ - ['3', '4'], - ['foo', '5'], - ]) - - expect(engine.getCellValue(adr('A1', 1))).toEqual('foo') - expect(engine.getCellValue(adr('A2', 1))).toBe(null) - }) - - it('should replace content of a sheet with formula matrix and recalculate range formula', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['1', '2'], - ['{=TRANSPOSE(A1:B1)}'], - ], - Sheet2: [ - ['=SUM(Sheet1!A1:A2)'], - ], - }) - - engine.setSheetContent(0, [ - ['3', '4'], - [null, '5'], - ]) - - expect(engine.getCellValue(adr('A1', 1))).toEqual(3) - }) -}) diff --git a/test/unit/cruds/set-column-order.spec.ts b/test/unit/cruds/set-column-order.spec.ts deleted file mode 100644 index 1050ef7213..0000000000 --- a/test/unit/cruds/set-column-order.spec.ts +++ /dev/null @@ -1,363 +0,0 @@ -import {HyperFormula, AlwaysSparse} from '../../../src' -import {adr} from '../testUtils' - -describe('swapping columns - checking if it is possible', () => { - it('should validate numbers for negative columns', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[-1, 0]])).toEqual(false) - expect(() => - engine.swapColumnIndexes(0, [[-1, 0]]) - ).toThrowError('Invalid arguments, expected column numbers to be nonnegative integers and less than sheet width.') - }) - - it('should validate sources for non-integer values', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[1, 1], [0.5, 0]])).toEqual(false) - expect(() => - engine.swapColumnIndexes(0, [[1, 1], [0.5, 0]]) - ).toThrowError('Invalid arguments, expected column numbers to be nonnegative integers and less than sheet width.') - }) - - it('should validate sources for values exceeding sheet width', () => { - const engine = HyperFormula.buildFromArray([[0, 0, 0]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[1, 1], [3, 0]])).toEqual(false) - expect(() => - engine.swapColumnIndexes(0, [[3, 0]]) - ).toThrowError('Invalid arguments, expected column numbers to be nonnegative integers and less than sheet width.') - }) - - it('should validate sources to be unique', () => { - const engine = HyperFormula.buildFromArray([[0, 0, 0]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 0], [1, 1], [1, 2]])).toEqual(false) - expect(() => - engine.swapColumnIndexes(0, [[0, 0], [1, 1], [1, 2]]) - ).toThrowError('Invalid arguments, expected source column numbers to be unique.') - }) - - it('should validate sources to be permutation of targets', () => { - const engine = HyperFormula.buildFromArray([[0, 0, 0]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 0], [1, 1], [2, 1]])).toEqual(false) - expect(() => - engine.swapColumnIndexes(0, [[0, 0], [1, 1], [2, 1]]) - ).toThrowError('Invalid arguments, expected target column numbers to be permutation of source column numbers.') - }) - - it('should check for matrices', () => { - const engine = HyperFormula.buildFromArray([[0, 0, '=TRANSPOSE(A1:B1)']]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 2], [1, 1], [2, 0]])).toEqual(false) - expect(() => - engine.swapColumnIndexes(0, [[0, 2], [1, 1], [2, 0]]) - ).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should check for matrices only in moved columns', () => { - const engine = HyperFormula.buildFromArray([[0, 0, '=TRANSPOSE(A1:B1)']]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 0], [2, 2]])).toEqual(true) - expect(() => - engine.swapColumnIndexes(0, [[0, 1], [1, 0], [2, 2]]) - ).not.toThrowError() - }) -}) - -describe('swapping columns should correctly work', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 'abcd'], [3, 3], [5, true]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 0]])).toEqual(true) - engine.swapColumnIndexes(0, [[0, 1], [1, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([['abcd', 1], [3, 3], [true, 5]]) - }) - - it('should return number of changed cells', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [3, 4], [5, 6]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 0]])).toEqual(true) - const ret = engine.swapColumnIndexes(0, [[0, 1], [1, 0]]) - expect(ret.length).toEqual(6) - }) - - it('should work on static engine with uneven column', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [3, 4], [5]], {chooseAddressMappingPolicy: new AlwaysSparse()}) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 0]])).toEqual(true) - engine.swapColumnIndexes(0, [[0, 1], [1, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[2, 1], [4, 3], [null, 5]]) - }) - - it('should work with more complicated permutations', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2], [6, 4, 5], [9, 7, 8]]) - }) - - it('should not move values unnecessarily', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 0], [1, 1]])).toEqual(true) - const ret = engine.swapColumnIndexes(0, [[0, 0], [1, 1]]) - expect(ret.length).toEqual(0) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2, '=A1', '=SUM(A2:A3)'], [6, 4, 5], [9, 7, 8]]) - expect(engine.getSheetValues(0)).toEqual([[3, 1, 2, 3, 15], [6, 4, 5], [9, 7, 8]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[3, '=B2', '=SUM(C2:C3)'], ['=#REF!', 1, '=SUM(C10:C15)'], [9, '=SUM(E1:E10)', 8]]) - }) -}) - -describe('swapping columns working with undo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - }) -}) - -describe('swapping columns working with redo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2], [6, 4, 5], [9, 7, 8]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2, '=A1', '=SUM(A2:A3)'], [6, 4, 5], [9, 7, 8]]) - expect(engine.getSheetValues(0)).toEqual([[3, 1, 2, 3, 15], [6, 4, 5], [9, 7, 8]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - engine.swapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.isItPossibleToSwapColumnIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[3, '=B2', '=SUM(C2:C3)'], ['=#REF!', 1, '=SUM(C10:C15)'], [9, '=SUM(E1:E10)', 8]]) - }) - - it('clears redo stack', () => { - const engine = HyperFormula.buildFromArray([[1]]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.swapColumnIndexes(0, [[0, 0]]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('setting column order - checking if it is possible', () => { - it('should check for length', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.isItPossibleToSetColumnOrder(0, [0])).toEqual(false) - expect(() => - engine.setColumnOrder(0, [0]) - ).toThrowError('Invalid arguments, expected number of columns provided to be sheet width.') - }) - - it('should validate sources for non-integer values', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.isItPossibleToSetColumnOrder(0, [0, 0.5])).toEqual(false) - expect(() => - engine.setColumnOrder(0, [0, 0.5]) - ).toThrowError('Invalid arguments, expected number of columns provided to be sheet width.') - }) - - it('should validate for repeated values', () => { - const engine = HyperFormula.buildFromArray([[0, 0, 0]]) - expect(engine.isItPossibleToSetColumnOrder(0, [0, 1, 1])).toEqual(false) - expect(() => - engine.setColumnOrder(0, [0, 1, 1]) - ).toThrowError('Invalid arguments, expected target column numbers to be permutation of source column numbers.') - }) - - it('should validate sources to be permutation of targets', () => { - const engine = HyperFormula.buildFromArray([[0, 0, 0]]) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 2, 3])).toEqual(false) - expect(() => - engine.setColumnOrder(0, [1, 2, 3]) - ).toThrowError('Invalid arguments, expected target column numbers to be permutation of source column numbers.') - }) - - it('should check for matrices', () => { - const engine = HyperFormula.buildFromArray([[0, 0, '=TRANSPOSE(A1:B1)']]) - expect(engine.isItPossibleToSetColumnOrder(0, [2, 1, 0])).toEqual(false) - expect(() => - engine.setColumnOrder(0, [2, 1, 0]) - ).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should check for matrices only in moved columns', () => { - const engine = HyperFormula.buildFromArray([[0, 0, '=TRANSPOSE(A1:B1)']]) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 0, 2])).toEqual(true) - expect(() => - engine.setColumnOrder(0, [1, 0, 2]) - ).not.toThrowError() - }) -}) - -describe('setColumnOrder', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 'abcd'], [3, 3], [5, true]]) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 0])).toEqual(true) - engine.setColumnOrder(0, [1, 0]) - expect(engine.getSheetSerialized(0)).toEqual([['abcd', 1], [3, 3], [true, 5]]) - }) - - it('should return number of changed cells', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [3, 4], [5, 6]]) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 0])).toEqual(true) - const ret = engine.setColumnOrder(0, [1, 0]) - expect(ret.length).toEqual(6) - }) - - it('should work on static engine with uneven column', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [3, 4], [5]], {chooseAddressMappingPolicy: new AlwaysSparse()}) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 0])).toEqual(true) - engine.setColumnOrder(0, [1, 0]) - expect(engine.getSheetSerialized(0)).toEqual([[2, 1], [4, 3], [null, 5]]) - }) - - it('should work with more complicated permutations', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 2, 0])).toEqual(true) - engine.setColumnOrder(0, [1, 2, 0]) - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2], [6, 4, 5], [9, 7, 8]]) - }) - - it('should work with strings', () => { - const hfInstance = HyperFormula.buildFromArray([ - ['A', 'B', 'C', 'D'] - ]) - - hfInstance.setColumnOrder(0, [0, 3, 2, 1]) - expect(hfInstance.getSheetSerialized(0)).toEqual([['A', 'D', 'C', 'B']]) - }) - - it('should not move values unnecessarily', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6]]) - expect(engine.isItPossibleToSetColumnOrder(0, [0, 1, 2])).toEqual(true) - const ret = engine.setColumnOrder(0, [0, 1, 2]) - expect(ret.length).toEqual(0) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 2, 0, 3, 4])).toEqual(true) - engine.setColumnOrder(0, [1, 2, 0, 3, 4]) - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2, '=A1', '=SUM(A2:A3)'], [6, 4, 5], [9, 7, 8]]) - expect(engine.getSheetValues(0)).toEqual([[3, 1, 2, 3, 15], [6, 4, 5], [9, 7, 8]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - expect(engine.isItPossibleToSetColumnOrder(0, [1, 2, 0, 3])).toEqual(true) - engine.setColumnOrder(0, [1, 2, 0, 3]) - expect(engine.getSheetSerialized(0)).toEqual([[3, '=B2', '=SUM(C2:C3)'], ['=#REF!', 1, '=SUM(C10:C15)'], [9, '=SUM(E1:E10)', 8]]) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards', () => { - const engine = HyperFormula.buildFromArray([[null, '=A1', 42]]) - engine.setColumnOrder(0, [1, 0, 2]) - engine.setCellContents(adr('A1'), '=B1') - expect(engine.getSheetSerialized(0)).toEqual([['=B1', null, 42]]) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards (with a range)', () => { - const engine = HyperFormula.buildFromArray([[null, null, null, '=SUM(A1:C1)', 42]]) - engine.setColumnOrder(0, [1, 2, 3, 0, 4]) - engine.setCellContents(adr('A1'), '=SUM(B1:D1)') - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(B1:D1)', null, null, null, 42]]) - }) -}) - -describe('reorder working with undo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.setColumnOrder(0, [1, 2, 0]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - engine.setColumnOrder(0, [1, 2, 0, 3, 4]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - engine.setColumnOrder(0, [1, 2, 0, 3]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - }) -}) - -describe('reorder working with redo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.setColumnOrder(0, [1, 2, 0]) - engine.undo() - expect(engine.isItPossibleToSetColumnOrder(0, [1, 2, 0])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2], [6, 4, 5], [9, 7, 8]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3, '=A1', '=SUM(A2:A3)'], [4, 5, 6], [7, 8, 9]]) - engine.setColumnOrder(0, [1, 2, 0, 3, 4]) - engine.undo() - expect(engine.isItPossibleToSetColumnOrder(0, [1, 2, 0, 3, 4])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[3, 1, 2, '=A1', '=SUM(A2:A3)'], [6, 4, 5], [9, 7, 8]]) - expect(engine.getSheetValues(0)).toEqual([[3, 1, 2, 3, 15], [6, 4, 5], [9, 7, 8]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], [1, '=SUM(B10:B15)', '=A10'], ['=SUM(D1:D10)', 8, 9]]) - engine.setColumnOrder(0, [1, 2, 0, 3]) - engine.undo() - expect(engine.isItPossibleToSetColumnOrder(0, [1, 2, 0, 3, 4])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[3, '=B2', '=SUM(C2:C3)'], ['=#REF!', 1, '=SUM(C10:C15)'], [9, '=SUM(E1:E10)', 8]]) - }) - - it('clears redo stack', () => { - const engine = HyperFormula.buildFromArray([[1]]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.setColumnOrder(0, [0]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) diff --git a/test/unit/cruds/set-matrix-empty.spec.ts b/test/unit/cruds/set-matrix-empty.spec.ts deleted file mode 100644 index b0b8e20fb4..0000000000 --- a/test/unit/cruds/set-matrix-empty.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import {HyperFormula} from '../../../src' -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {adr} from '../testUtils' - -describe('Set matrix empty', () => { - it('should set matrix empty', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - const dependencyGraph = engine.dependencyGraph - - const matrixVertex = dependencyGraph.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2))! - - dependencyGraph.setArrayEmpty(matrixVertex) - - expect(engine.getCellValue(adr('A2'))).toBe(null) - expect(engine.getCellValue(adr('A3'))).toBe(null) - expect(dependencyGraph.arrayMapping.arrayMapping.size).toEqual(0) - }) - - it('should adjust edges between matrix cells and formula', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A1+A2'], - ['=TRANSPOSE(A1:B1)'], - ]) - const dependencyGraph = engine.dependencyGraph - - const matrixVertex = dependencyGraph.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2))! - - dependencyGraph.setArrayEmpty(matrixVertex) - - expect(engine.getCellValue(adr('A2'))).toBe(null) - expect(engine.getCellValue(adr('A3'))).toBe(null) - expect(dependencyGraph.arrayMapping.arrayMapping.size).toEqual(0) - - const formula = dependencyGraph.fetchCell(adr('C1')) - const a1 = dependencyGraph.fetchCell(adr('A1')) - const a2 = dependencyGraph.fetchCell(adr('A2')) - const a3 = dependencyGraph.getCell(adr('A3')) - expect(dependencyGraph.existsEdge(matrixVertex, formula)).toBe(false) - expect(dependencyGraph.existsEdge(a1, formula)).toBe(true) - expect(dependencyGraph.existsEdge(a2, formula)).toBe(true) - expect(a3).toBe(undefined) - }) - - it('should adjust edges between matrix cells and formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=TRANSPOSE(A1:B1)'], - ['=TRANSPOSE(A1:B1)'], - ]) - const dependencyGraph = engine.dependencyGraph - - const matrixVertex = dependencyGraph.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2))! - - dependencyGraph.setArrayEmpty(matrixVertex) - - expect(engine.getCellValue(adr('A2'))).toBe(null) - expect(engine.getCellValue(adr('A3'))).toBe(null) - expect(dependencyGraph.arrayMapping.arrayMapping.size).toEqual(1) - - const formulaMatrix = dependencyGraph.fetchCell(adr('C1')) - const a1 = dependencyGraph.fetchCell(adr('A1')) - expect(dependencyGraph.existsEdge(matrixVertex, formulaMatrix)).toBe(false) - expect(dependencyGraph.existsEdge(a1, formulaMatrix)).toBe(false) - }) - - it('should adjust edges between matrix cells and range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A2:A3)'], - ['=TRANSPOSE(A1:B1)'], - ]) - const dependencyGraph = engine.dependencyGraph - - const matrixVertex = dependencyGraph.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2))! - - const rangeVertex = dependencyGraph.rangeMapping.getRangeVertex(adr('A2'), adr('A3'))! - expect(dependencyGraph.existsEdge(matrixVertex, rangeVertex)).toBe(true) - - dependencyGraph.setArrayEmpty(matrixVertex) - - expect(dependencyGraph.arrayMapping.arrayMapping.size).toEqual(0) - - const formula = dependencyGraph.fetchCell(adr('C1')) - const a2 = dependencyGraph.fetchCell(adr('A2')) - const a3 = dependencyGraph.fetchCell(adr('A3')) - expect(a2).not.toBe(a3) - expect(dependencyGraph.existsEdge(rangeVertex, formula)).toBe(true) - expect(dependencyGraph.existsEdge(matrixVertex, rangeVertex)).toBe(false) - expect(dependencyGraph.existsEdge(a2, rangeVertex)).toBe(true) - expect(dependencyGraph.existsEdge(a3, rangeVertex)).toBe(true) - }) - - it('should adjust edges between matrix cells and range crossing matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=SUM(A1:A2)'], - ['=TRANSPOSE(A1:B1)'], - ]) - const dependencyGraph = engine.dependencyGraph - - const matrixVertex = dependencyGraph.arrayMapping.getArray(AbsoluteCellRange.spanFrom(adr('A2'), 1, 2))! - - const rangeVertex = dependencyGraph.rangeMapping.getRangeVertex(adr('A1'), adr('A2'))! - expect(dependencyGraph.existsEdge(matrixVertex, rangeVertex)).toBe(true) - - dependencyGraph.setArrayEmpty(matrixVertex) - - expect(dependencyGraph.arrayMapping.arrayMapping.size).toEqual(0) - - const formula = dependencyGraph.fetchCell(adr('C1')) - const a1 = dependencyGraph.fetchCell(adr('A1')) - const a2 = dependencyGraph.fetchCell(adr('A2')) - const a3 = dependencyGraph.getCell(adr('A3')) - expect(dependencyGraph.existsEdge(rangeVertex, formula)).toBe(true) - expect(dependencyGraph.existsEdge(matrixVertex, rangeVertex)).toBe(false) - expect(dependencyGraph.existsEdge(a1, rangeVertex)).toBe(true) - expect(dependencyGraph.existsEdge(a2, rangeVertex)).toBe(true) - expect(a3).toBe(undefined) - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) -}) diff --git a/test/unit/cruds/set-row-order.spec.ts b/test/unit/cruds/set-row-order.spec.ts deleted file mode 100644 index fcf3137d17..0000000000 --- a/test/unit/cruds/set-row-order.spec.ts +++ /dev/null @@ -1,390 +0,0 @@ -import {HyperFormula, AlwaysSparse} from '../../../src' -import {adr} from '../testUtils' - -describe('swapping rows - checking if it is possible', () => { - it('should validate numbers for negative rows', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[-1, 0]])).toEqual(false) - expect(() => - engine.swapRowIndexes(0, [[-1, 0]]) - ).toThrowError('Invalid arguments, expected row numbers to be nonnegative integers and less than sheet height.') - }) - - it('should validate sources for non-integer values', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[1, 1], [0.5, 0]])).toEqual(false) - expect(() => - engine.swapRowIndexes(0, [[1, 1], [0.5, 0]]) - ).toThrowError('Invalid arguments, expected row numbers to be nonnegative integers and less than sheet height.') - }) - - it('should validate sources for values exceeding sheet height', () => { - const engine = HyperFormula.buildFromArray([[0], [0], [0]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[1, 1], [3, 0]])).toEqual(false) - expect(() => - engine.swapRowIndexes(0, [[3, 0]]) - ).toThrowError('Invalid arguments, expected row numbers to be nonnegative integers and less than sheet height.') - }) - - it('should validate sources to be unique', () => { - const engine = HyperFormula.buildFromArray([[0], [0], [0]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 0], [1, 1], [1, 2]])).toEqual(false) - expect(() => - engine.swapRowIndexes(0, [[0, 0], [1, 1], [1, 2]]) - ).toThrowError('Invalid arguments, expected source row numbers to be unique.') - }) - - it('should validate sources to be permutation of targets', () => { - const engine = HyperFormula.buildFromArray([[0], [0], [0]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 0], [1, 1], [2, 1]])).toEqual(false) - expect(() => - engine.swapRowIndexes(0, [[0, 0], [1, 1], [2, 1]]) - ).toThrowError('Invalid arguments, expected target row numbers to be permutation of source row numbers.') - }) - - it('should check for matrices', () => { - const engine = HyperFormula.buildFromArray([[0], [0], ['=TRANSPOSE(A1:A2)']]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 2], [1, 1], [2, 0]])).toEqual(false) - expect(() => - engine.swapRowIndexes(0, [[0, 2], [1, 1], [2, 0]]) - ).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should check for matrices only in moved rows', () => { - const engine = HyperFormula.buildFromArray([[0], [0], ['=TRANSPOSE(A1:A2)']]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 0], [2, 2]])).toEqual(true) - expect(() => - engine.swapRowIndexes(0, [[0, 1], [1, 0], [2, 2]]) - ).not.toThrowError() - }) -}) - -describe('swapping rows should correctly work', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 'abcd', 3], [3, 5, true]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 0]])).toEqual(true) - engine.swapRowIndexes(0, [[0, 1], [1, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[3, 5, true], [1, 'abcd', 3]]) - }) - - it('should return number of changed cells', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 0]])).toEqual(true) - const ret = engine.swapRowIndexes(0, [[0, 1], [1, 0]]) - expect(ret.length).toEqual(6) - }) - - it('should work on static engine with uneven rows', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6, 7, 8]], {chooseAddressMappingPolicy: new AlwaysSparse()}) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 0]])).toEqual(true) - engine.swapRowIndexes(0, [[0, 1], [1, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[4, 5, 6, 7, 8], [1, 2, 3]]) - }) - - it('should work with more complicated permutations', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6]]) - }) - - it('should not move values unnecessarily', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 0], [1, 1]])).toEqual(true) - const ret = engine.swapRowIndexes(0, [[0, 0], [1, 1]]) - expect(ret.length).toEqual(0) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], ['=A1', '=SUM(A2:A3)']]) - expect(engine.getSheetValues(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 5]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(#REF!)', 8, 9], ['=A3', '=SUM(B3:B4)', 3], ['=A11', '=SUM(B11:B16)', 6]]) - }) -}) - -describe('swapping rows working with undo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - }) -}) - -describe('swapping rows working with redo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], ['=A1', '=SUM(A2:A3)']]) - expect(engine.getSheetValues(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 5]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - engine.swapRowIndexes(0, [[0, 1], [1, 2], [2, 0]]) - engine.undo() - expect(engine.isItPossibleToSwapRowIndexes(0, [[0, 1], [1, 2], [2, 0]])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(#REF!)', 8, 9], ['=A3', '=SUM(B3:B4)', 3], ['=A11', '=SUM(B11:B16)', 6]]) - }) - - it('clears redo stack', () => { - const engine = HyperFormula.buildFromArray([[1]]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.swapRowIndexes(0, [[0, 0]]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -function fillValues(order: number[], fill: number): number[] { - while (order.length < fill) { - const x = order.length - order[x] = x - } - return order -} - -describe('setting row order - checking if it is possible', () => { - it('should check for length', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.isItPossibleToSetRowOrder(0, [0])).toEqual(false) - expect(() => - engine.setRowOrder(0, [0]) - ).toThrowError('Invalid arguments, expected number of rows provided to be sheet height.') - }) - - it('should validate sources for non-integer values', () => { - const engine = HyperFormula.buildFromArray([[0], [0]]) - expect(engine.isItPossibleToSetRowOrder(0, [0, 0.5])).toEqual(false) - expect(() => - engine.setRowOrder(0, [0, 0.5]) - ).toThrowError('Invalid arguments, expected target row numbers to be permutation of source row numbers.') - }) - - it('should validate for repeated values', () => { - const engine = HyperFormula.buildFromArray([[0], [0], [0]]) - expect(engine.isItPossibleToSetRowOrder(0, [0, 1, 1])).toEqual(false) - expect(() => - engine.setRowOrder(0, [0, 1, 1]) - ).toThrowError('Invalid arguments, expected target row numbers to be permutation of source row numbers.') - }) - - it('should validate sources to be permutation of targets', () => { - const engine = HyperFormula.buildFromArray([[0], [0], [0]]) - expect(engine.isItPossibleToSetRowOrder(0, [1, 2, 3])).toEqual(false) - expect(() => - engine.setRowOrder(0, [1, 2, 3]) - ).toThrowError('Invalid arguments, expected target row numbers to be permutation of source row numbers.') - }) - - it('should check for matrices', () => { - const engine = HyperFormula.buildFromArray([[0], [0], ['=TRANSPOSE(A1:A2)']]) - expect(engine.isItPossibleToSetRowOrder(0, [2, 1, 0])).toEqual(false) - expect(() => - engine.setRowOrder(0, [2, 1, 0]) - ).toThrowError('Cannot perform this operation, source location has an array inside.') - }) - - it('should check for matrices only in moved rows', () => { - const engine = HyperFormula.buildFromArray([[0], [0], ['=TRANSPOSE(A1:A2)']]) - expect(engine.isItPossibleToSetRowOrder(0, [1, 0, 2])).toEqual(true) - expect(() => - engine.setRowOrder(0, [1, 0, 2]) - ).not.toThrowError() - }) -}) - -describe('reorder base case', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 'abcd', 3], [3, 5, true]]) - expect(engine.isItPossibleToSetRowOrder(0, [1, 0])).toEqual(true) - engine.setRowOrder(0, [1, 0]) - expect(engine.getSheetSerialized(0)).toEqual([[3, 5, true], [1, 'abcd', 3]]) - }) - - it('should return number of changed cells', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6]]) - expect(engine.isItPossibleToSetRowOrder(0, [1, 0])).toEqual(true) - const ret = engine.setRowOrder(0, [1, 0]) - expect(ret.length).toEqual(6) - }) - - it('should work on static engine with uneven rows', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6, 7, 8]], {chooseAddressMappingPolicy: new AlwaysSparse()}) - expect(engine.isItPossibleToSetRowOrder(0, [1, 0])).toEqual(true) - engine.setRowOrder(0, [1, 0]) - expect(engine.getSheetSerialized(0)).toEqual([[4, 5, 6, 7, 8], [1, 2, 3]]) - }) - - it('should work with more complicated permutations', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - expect(engine.isItPossibleToSetRowOrder(0, [1, 2, 0])).toEqual(true) - engine.setRowOrder(0, [1, 2, 0]) - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6]]) - }) - - it('should work with strings', () => { - const hfInstance = HyperFormula.buildFromArray([ - ['A'], - ['B'], - ['C'], - ['D'] - ]) - - hfInstance.setRowOrder(0, [0, 3, 2, 1]) - expect(hfInstance.getSheetSerialized(0)).toEqual([['A'], ['D'], ['C'], ['B']]) - }) - - it('should update the addressing in cells being sorted', () => { - const engine = HyperFormula.buildFromArray([[1, 2, '=A1+B1'], [4, 5, '=A2+B2'], [7, 8, '=A3+B3']]) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3], [4, 5, 9], [7, 8, 15]]) - expect(engine.isItPossibleToSetRowOrder(0, [1, 2, 0])).toEqual(true) - engine.setRowOrder(0, [1, 2, 0]) - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, '=A1+B1'], [1, 2, '=A2+B2'], [4, 5, '=A3+B3']]) - expect(engine.getSheetValues(0)).toEqual([[7, 8, 15], [1, 2, 3], [4, 5, 9]]) - }) - - it('should not change the constants in formulas when updating addresses', () => { - const engine = HyperFormula.buildFromArray([[1, 2, '=1+A1'], [4, 5, '=2+A2'], [7, 8, '=3+A3']]) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 2], [4, 5, 6], [7, 8, 10]]) - expect(engine.isItPossibleToSetRowOrder(0, [1, 2, 0])).toEqual(true) - engine.setRowOrder(0, [1, 2, 0]) - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, '=3+A1'], [1, 2, '=1+A2'], [4, 5, '=2+A3']]) - expect(engine.getSheetValues(0)).toEqual([[7, 8, 10], [1, 2, 2], [4, 5, 6]]) - }) - - it('should not move values unnecessarily', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6]]) - expect(engine.isItPossibleToSetRowOrder(0, [0, 1])).toEqual(true) - const ret = engine.setRowOrder(0, [0, 1]) - expect(ret.length).toEqual(0) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - engine.setRowOrder(0, [1, 2, 0, 3]) - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], ['=A1', '=SUM(A2:A3)']]) - expect(engine.getSheetValues(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 5]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - expect(engine.isItPossibleToSetRowOrder(0, fillValues([1, 2, 0], 15))).toEqual(true) - engine.setRowOrder(0, fillValues([1, 2, 0], 15)) - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(#REF!)', 8, 9], ['=A3', '=SUM(B3:B4)', 3], ['=A11', '=SUM(B11:B16)', 6]]) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards', () => { - const engine = HyperFormula.buildFromArray([[null], ['=A1']]) - engine.setRowOrder(0, [1, 0]) - engine.setCellContents(adr('A1'), '=A2') - expect(engine.getSheetSerialized(0)).toEqual([['=A2']]) - }) - - it('leaves the engine in a valid state so other operations are possible afterwards (with a range)', () => { - const engine = HyperFormula.buildFromArray([[null, null, null], ['=SUM(A1:C1)']]) - engine.setRowOrder(0, [1, 0]) - engine.setCellContents(adr('A1'), '=SUM(A2:C2)') - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(A2:C2)']]) - }) -}) - -describe('reorder working with undo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.setRowOrder(0, [1, 2, 0]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - engine.setRowOrder(0, [1, 2, 0, 3]) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - engine.setRowOrder(0, fillValues([1, 2, 0], 15)) - engine.undo() - expect(engine.getSheetSerialized(0)).toEqual([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - }) -}) - -describe('reorder working with redo', () => { - it('should work on static engine', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - engine.setRowOrder(0, [1, 2, 0]) - engine.undo() - expect(engine.isItPossibleToSetRowOrder(0, [1, 2, 0])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6]]) - }) - - it('should work with external references', () => { - const engine = HyperFormula.buildFromArray([[1, 2, 3], [4, 5, 6], [7, 8, 9], ['=A1', '=SUM(A2:A3)']]) - engine.setRowOrder(0, [1, 2, 0, 3]) - engine.undo() - expect(engine.isItPossibleToSetRowOrder(0, [1, 2, 0, 3])).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], ['=A1', '=SUM(A2:A3)']]) - expect(engine.getSheetValues(0)).toEqual([[7, 8, 9], [1, 2, 3], [4, 5, 6], [7, 5]]) - }) - - it('should work with internal references', () => { - const engine = HyperFormula.buildFromArray([['=A2', '=SUM(B2:B3)', 3], ['=A10', '=SUM(B10:B15)', 6], ['=SUM(C1:C10)', 8, 9]]) - engine.setRowOrder(0, fillValues([1, 2, 0], 15)) - engine.undo() - expect(engine.isItPossibleToSetRowOrder(0, fillValues([1, 2, 0], 16))).toEqual(true) - engine.redo() - expect(engine.getSheetSerialized(0)).toEqual([['=SUM(#REF!)', 8, 9], ['=A3', '=SUM(B3:B4)', 3], ['=A11', '=SUM(B11:B16)', 6]]) - }) - - it('clears redo stack', () => { - const engine = HyperFormula.buildFromArray([[1]]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.setRowOrder(0, [0]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) diff --git a/test/unit/custom-functions.spec.ts b/test/unit/custom-functions.spec.ts deleted file mode 100644 index 4dbe70cbe8..0000000000 --- a/test/unit/custom-functions.spec.ts +++ /dev/null @@ -1,682 +0,0 @@ -import { - CellError, - ErrorType, - FunctionArgumentType, - FunctionPluginValidationError, - HyperFormula, - SimpleRangeValue, - ArraySize, -} from '../../src' -import {ErrorMessage} from '../../src/error-message' -import {AliasAlreadyExisting, ProtectedFunctionError, ProtectedFunctionTranslationError} from '../../src/errors' -import {plPL} from '../../src/i18n/languages' -import {InterpreterState} from '../../src/interpreter/InterpreterState' -import {InternalScalarValue} from '../../src/interpreter/InterpreterValue' -import {FunctionPlugin, FunctionPluginTypecheck} from '../../src/interpreter/plugin/FunctionPlugin' -import {ConditionalAggregationPlugin, NumericAggregationPlugin} from '../../src/interpreter/plugin' -import {VersionPlugin} from '../../src/interpreter/plugin/VersionPlugin' -import {ProcedureAst} from '../../src/parser' -import {adr, detailedError, expectArrayWithSameContent, resetSpy} from './testUtils' - -class FooPlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'FOO': { - method: 'foo', - }, - 'BAR': { - method: 'bar', - }, - 'ARRAYFOO': { - method: 'arrayfoo', - sizeOfResultArrayMethod: 'arraysizeFoo', - parameters: [{ argumentType: FunctionArgumentType.NUMBER }], - }, - } - - public static translations = { - 'enGB': { - 'FOO': 'FOO', - 'BAR': 'BAR', - 'ARRAYFOO': 'ARRAYFOO', - }, - 'plPL': { - 'FOO': 'FU', - 'BAR': 'BAR', - 'ARRAYFOO': 'ARRAYFOO', - } - } - - public foo(_ast: ProcedureAst, _state: InterpreterState): InternalScalarValue { - return 'foo' - } - - public bar(_ast: ProcedureAst, _state: InterpreterState): InternalScalarValue { - return 'bar' - } - - public arrayfoo(_ast: ProcedureAst, _state: InterpreterState): SimpleRangeValue { - return SimpleRangeValue.onlyValues([[1, 1], [1, 1]]) - } - - public arraysizeFoo(_ast: ProcedureAst, _state: InterpreterState): ArraySize { - return new ArraySize(2, 2) - } -} - -class SumWithExtra extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'SUM': { - method: 'sum', - } - } - - public static aliases = { - 'SUMALIAS': 'SUM', - } - - public sum(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { - const left = this.evaluateAst(ast.args[0], state) as number - const right = this.evaluateAst(ast.args[1], state) as number - return 42 + left + right - } -} - -class InvalidPlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'FOO': { - method: 'foo', - } - } - - public bar(_ast: ProcedureAst, _state: InterpreterState): InternalScalarValue { - return 'bar' - } -} - -class EmptyAliasPlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'FOO': { - method: 'foo', - } - } - - public static aliases = { - 'FOOALIAS': 'BAR', - } -} - -class OverloadedAliasPlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'FOO': { - method: 'foo', - }, - 'BAR': { - method: 'foo', - } - } - - public static aliases = { - 'FOO': 'BAR', - } -} - -class ReservedNamePlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'VERSION': { - method: 'version', - } - } - - public version(_ast: ProcedureAst, _state: InterpreterState): InternalScalarValue { - return 'foo' - } -} - -class SquarePlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - // Key of the mapping describes which function will be used to compute it - 'SQUARE': { - method: 'square', - }, - } - - public square(ast: ProcedureAst, state: InterpreterState): InternalScalarValue { - // Take ast of first argument from list of arguments - const arg = ast.args[0] - - // If there was no argument, return NA error - if (!arg) { - return new CellError(ErrorType.NA) - } - - // Compute value of argument - const argValue = this.evaluateAst(arg, state) - - if (argValue instanceof CellError) { - // If the value is some error, return that error - return argValue - } else if (typeof argValue === 'number') { - // If it's a number, compute the result - return (argValue * argValue) - } else { - // If it's some other type which doesn't make sense in terms of square (string, boolean), return VALUE error - return new CellError(ErrorType.VALUE) - } - } -} - -class GreetingsPlugin extends FunctionPlugin { - public static implementedFunctions = { - GREET: { - method: 'greet', - parameters: [ - { argumentType: FunctionArgumentType.STRING } - ], - }, - EXAMPLE_ARRAY_FUNCTION: { - method: 'exampleArrayFunction', - parameters: [ - { argumentType: FunctionArgumentType.NUMBER } - ], - } - } - - public static translations = { - enGB: { - GREET: 'GREET', - EXAMPLE_ARRAY_FUNCTION: 'EXAMPLE_ARRAY_FUNCTION', - }, - enUS: { - GREET: 'GREET', - EXAMPLE_ARRAY_FUNCTION: 'EXAMPLE_ARRAY_FUNCTION', - } - } - - greet(ast: ProcedureAst, state: InterpreterState) { - return this.runFunction( - ast.args, - state, - this.metadata('GREET'), - (username) => { - if (!username) { - return new CellError(ErrorType.VALUE) - } - - return `👋 Hello, ${username}!` - }, - ) - } - - exampleArrayFunction(ast: ProcedureAst, state: InterpreterState) { - return this.runFunction( - ast.args, - state, - this.metadata('EXAMPLE_ARRAY_FUNCTION'), - (val: number) => { - return SimpleRangeValue.onlyValues([[val, val], [val, val]]) - }, - ) - } -} - -class ContextPlugin extends FunctionPlugin { - public static implementedFunctions = { - 'GETCONTEXT': { - method: 'getContext', - } - } - - public getContext(ast: ProcedureAst, state: InterpreterState): unknown { - return this.config.context - } -} - -describe('Register static custom plugin', () => { - it('should register plugin with translations', () => { - HyperFormula.registerLanguage('plPL', plPL) - HyperFormula.registerFunctionPlugin(FooPlugin, FooPlugin.translations) - - const pl = HyperFormula.getLanguage('plPL') - - expect(pl.getFunctionTranslation('FOO')).toEqual('FU') - }) - - it('should register single function with translations', () => { - HyperFormula.registerFunction('FOO', FooPlugin, FooPlugin.translations) - - const engine = HyperFormula.buildFromArray([['=FOO()']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - }) - - it('registerFunction should not affect the existing HyperFormula instances', () => { - const engine = HyperFormula.buildFromArray([['=FOO()']]) - HyperFormula.registerFunction('FOO', FooPlugin, FooPlugin.translations) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOO'))) - }) - - it('registerFunctionPlugin should not affect the existing HyperFormula instances', () => { - const engine = HyperFormula.buildFromArray([['=FOO()']]) - HyperFormula.registerFunctionPlugin(FooPlugin, FooPlugin.translations) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOO'))) - }) - - it('should return registered formula translations', () => { - HyperFormula.unregisterAllFunctions() - HyperFormula.registerLanguage('plPL', plPL) - HyperFormula.registerFunctionPlugin(ConditionalAggregationPlugin) - HyperFormula.registerFunctionPlugin(FooPlugin, FooPlugin.translations) - const formulaNames = HyperFormula.getRegisteredFunctionNames('plPL') - - expectArrayWithSameContent(['FU', 'BAR', 'ARRAYFOO', 'SUMA.JEŻELI', 'LICZ.JEŻELI', 'ŚREDNIA.JEŻELI', 'SUMY.JEŻELI', 'LICZ.WARUNKI', 'VERSION', 'PRZESUNIĘCIE', 'MAKS.WARUNKÓW', 'MIN.WARUNKÓW'], formulaNames) - }) - - it('should register all formulas from plugin', () => { - HyperFormula.registerFunctionPlugin(FooPlugin, FooPlugin.translations) - - const engine = HyperFormula.buildFromArray([ - ['=foo()', '=bar()'] - ]) - - expect(HyperFormula.getRegisteredFunctionNames('enGB')).toContain('FOO') - expect(HyperFormula.getRegisteredFunctionNames('enGB')).toContain('BAR') - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('B1'))).toEqual('bar') - }) - - it('should register single formula from plugin', () => { - HyperFormula.registerFunction('BAR', FooPlugin, FooPlugin.translations) - const engine = HyperFormula.buildFromArray([ - ['=foo()', '=bar()'] - ]) - - expect(HyperFormula.getRegisteredFunctionNames('enGB')).not.toContain('FOO') - expect(HyperFormula.getRegisteredFunctionNames('enGB')).toContain('BAR') - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOO'))) - expect(engine.getCellValue(adr('B1'))).toEqual('bar') - }) - - it('should register single array functions', () => { - HyperFormula.registerFunction('ARRAYFOO', FooPlugin, FooPlugin.translations) - const engine = HyperFormula.buildFromArray([ - ['=ARRAYFOO(0)'] - ]) - - expect(engine.getSheetValues(0)).toEqual([[1, 1], [1, 1]]) - }) - - it('should override one formula with custom implementation', () => { - HyperFormula.registerFunction('SUM', SumWithExtra) - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, 2)', '=MAX(1, 2)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(45) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - }) - - it('should allow to register only alias', () => { - HyperFormula.registerFunction('SUMALIAS', SumWithExtra, {'enGB': {'SUMALIAS': 'SUMALIAS'}}) - const engine = HyperFormula.buildFromArray([ - ['=SUMALIAS(1, 2)', '=MAX(1, 2)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(45) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - }) - - it('should throw plugin validation error', () => { - expect(() => { - HyperFormula.registerFunctionPlugin(InvalidPlugin) - }).toThrow(FunctionPluginValidationError.functionMethodNotFound('foo', 'InvalidPlugin')) - - expect(() => { - HyperFormula.registerFunction('FOO', InvalidPlugin) - }).toThrow(FunctionPluginValidationError.functionMethodNotFound('foo', 'InvalidPlugin')) - - expect(() => { - HyperFormula.registerFunction('BAR', InvalidPlugin) - }).toThrow(FunctionPluginValidationError.functionNotDeclaredInPlugin('BAR', 'InvalidPlugin')) - }) - - it('should return registered plugins', () => { - HyperFormula.unregisterAllFunctions() - HyperFormula.registerFunctionPlugin(ConditionalAggregationPlugin) - HyperFormula.registerFunctionPlugin(NumericAggregationPlugin) - HyperFormula.registerFunctionPlugin(SumWithExtra) - - expectArrayWithSameContent(HyperFormula.getAllFunctionPlugins(), [ConditionalAggregationPlugin, NumericAggregationPlugin, SumWithExtra]) - }) - - it('should unregister whole plugin', () => { - HyperFormula.unregisterAllFunctions() - HyperFormula.registerFunctionPlugin(NumericAggregationPlugin) - HyperFormula.registerFunctionPlugin(ConditionalAggregationPlugin) - - HyperFormula.unregisterFunctionPlugin(NumericAggregationPlugin) - - expectArrayWithSameContent(HyperFormula.getAllFunctionPlugins(), [ConditionalAggregationPlugin]) - }) - - it('should return plugin for given functionId', () => { - expect(HyperFormula.getFunctionPlugin('SUMIF')).toBe(ConditionalAggregationPlugin) - }) - - it('should clear function registry', () => { - expect(HyperFormula.getRegisteredFunctionNames('enGB').length).toBeGreaterThan(0) - - HyperFormula.unregisterAllFunctions() - - expect(HyperFormula.getRegisteredFunctionNames('enGB').length).toEqual(2) // protected functions counts - }) -}) - -describe('Instance level formula registry', () => { - beforeEach(() => { - HyperFormula.getLanguage('enGB').extendFunctions({FOO: 'FOO'}) - HyperFormula.getLanguage('enGB').extendFunctions({BAR: 'BAR'}) - }) - - it('should return registered formula ids', () => { - const engine = HyperFormula.buildFromArray([], {functionPlugins: [FooPlugin, SumWithExtra]}) - - expectArrayWithSameContent(engine.getRegisteredFunctionNames(), ['SUM', 'FOO', 'BAR', 'VERSION']) - }) - - it('should create engine only with plugins passed to configuration', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo()', '=bar()', '=SUM(1, 2)'] - ], {functionPlugins: [FooPlugin]}) - - expectArrayWithSameContent(['FOO', 'BAR', 'VERSION'], engine.getRegisteredFunctionNames()) - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('B1'))).toEqual('bar') - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('SUM'))) - }) - - it('modifying static plugins should not affect existing engine instance registry', () => { - HyperFormula.registerFunctionPlugin(FooPlugin) - const engine = HyperFormula.buildFromArray([ - ['=foo()', '=bar()'] - ]) - HyperFormula.unregisterFunction('FOO') - - engine.setCellContents(adr('C1'), '=A1') - - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('B1'))).toEqual('bar') - expect(engine.getCellValue(adr('C1'))).toEqual('foo') - }) - - it('should return registered plugins', () => { - const engine = HyperFormula.buildFromArray([], {functionPlugins: [ConditionalAggregationPlugin, NumericAggregationPlugin, SumWithExtra]}) - - expectArrayWithSameContent(engine.getAllFunctionPlugins(), [ConditionalAggregationPlugin, NumericAggregationPlugin, SumWithExtra]) - }) - - it('should instantiate engine with additional plugin', () => { - const engine = HyperFormula.buildFromArray([], { - functionPlugins: [...HyperFormula.getAllFunctionPlugins(), FooPlugin] - }) - - const registeredPlugins = new Set(engine.getAllFunctionPlugins()) - - expect(registeredPlugins.size).toEqual(HyperFormula.getAllFunctionPlugins().length + 1) - expect(registeredPlugins.has(FooPlugin)).toBe(true) - }) - - it('should rebuild engine and override plugins', () => { - const engine = HyperFormula.buildFromArray([]) - - let registeredPlugins = new Set(engine.getAllFunctionPlugins()) - expect(registeredPlugins.has(ConditionalAggregationPlugin)).toBe(true) - expect(registeredPlugins.has(FooPlugin)).toBe(false) - - engine.updateConfig({functionPlugins: [FooPlugin]}) - registeredPlugins = new Set(engine.getAllFunctionPlugins()) - expect(registeredPlugins.has(FooPlugin)).toBe(true) - expect(registeredPlugins.size).toBe(1) - }) - - it('should return plugin for given functionId', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.getFunctionPlugin('SUMIF')).toBe(ConditionalAggregationPlugin) - }) -}) - -describe('Reserved functions', () => { - it('should not be possible to remove reserved function', () => { - expect(() => { - HyperFormula.unregisterFunction('VERSION') - }).toThrow(ProtectedFunctionError.cannotUnregisterFunctionWithId('VERSION')) - }) - - it('should not be possible to unregister reserved plugin', () => { - expect(() => { - HyperFormula.unregisterFunctionPlugin(VersionPlugin) - }).toThrow(ProtectedFunctionError.cannotUnregisterProtectedPlugin()) - }) - - it('should not be possible to override reserved function', () => { - expect(() => { - HyperFormula.registerFunction('VERSION', ReservedNamePlugin) - }).toThrow(ProtectedFunctionError.cannotRegisterFunctionWithId('VERSION')) - - expect(() => { - HyperFormula.registerFunctionPlugin(ReservedNamePlugin) - }).toThrow(ProtectedFunctionError.cannotRegisterFunctionWithId('VERSION')) - }) - - it('should return undefined when trying to retrieve protected function plugin', () => { - expect(HyperFormula.getFunctionPlugin('VERSION')).toBe(undefined) - }) - - it('should not be possible to override protected function translation when registering plugin', () => { - expect(() => { - HyperFormula.registerFunction('FOO', FooPlugin, {'enGB': {'VERSION': 'FOOBAR'}}) - }).toThrow(new ProtectedFunctionTranslationError('VERSION')) - - expect(() => { - HyperFormula.registerFunctionPlugin(FooPlugin, {'enGB': {'VERSION': 'FOOBAR'}}) - }).toThrow(new ProtectedFunctionTranslationError('VERSION')) - }) -}) - -describe('aliases', () => { - it('should validate that alias target exists', () => { - expect(() => { - HyperFormula.registerFunctionPlugin(EmptyAliasPlugin) - }).toThrow(FunctionPluginValidationError.functionMethodNotFound('foo', 'EmptyAliasPlugin')) - }) - - it('should validate that alias key is available', () => { - expect(() => { - HyperFormula.registerFunctionPlugin(OverloadedAliasPlugin) - }).toThrow(new AliasAlreadyExisting('FOO', 'OverloadedAliasPlugin')) - }) -}) - -describe('Argument validation implemented by hand (without call to runFunction)', () => { - it('works', () => { - HyperFormula.registerFunctionPlugin(SquarePlugin) - HyperFormula.getLanguage('enGB').extendFunctions({SQUARE: 'SQUARE'}) - - const engine = HyperFormula.buildFromArray([ - ['=SQUARE(2)'], - ['=SQUARE()'], - ['=SQUARE(TRUE())'], - ['=SQUARE(1/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) - -describe('Custom function implemented with runFunction)', () => { - it('works for a non-empty string', () => { - HyperFormula.registerFunctionPlugin(GreetingsPlugin, GreetingsPlugin.translations) - - const engine = HyperFormula.buildFromArray([['Anthony', '=GREET(A1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual('👋 Hello, Anthony!') - }) - - it('returns #VALUE! error for empty string', () => { - HyperFormula.registerFunctionPlugin(GreetingsPlugin, GreetingsPlugin.translations) - - const engine = HyperFormula.buildFromArray([['', '=GREET(A1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE)) - }) - - it('propagates #DIV_BY_ZERO! error', () => { - HyperFormula.registerFunctionPlugin(GreetingsPlugin, GreetingsPlugin.translations) - - const engine = HyperFormula.buildFromArray([['=1/0', '=GREET(A1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('propagates #CYCLE! error', () => { - HyperFormula.registerFunctionPlugin(GreetingsPlugin, GreetingsPlugin.translations) - - const engine = HyperFormula.buildFromArray([['=B1', '=GREET(A1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) - - it('function returning array throws error when user tries to vectorize it', () => { - HyperFormula.registerFunctionPlugin(GreetingsPlugin, GreetingsPlugin.translations) - - expect(() => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=EXAMPLE_ARRAY_FUNCTION(A1:C1)'], - ], {useArrayArithmetic: true}) - - engine.getCellValue(adr('A2')) - }).toThrow(new Error('Function returning array cannot be vectorized.')) - }) -}) - -describe('Context accessible within custom function', () => { - it('works', () => { - HyperFormula.registerFunctionPlugin(ContextPlugin) - HyperFormula.getLanguage('enGB').extendFunctions({GETCONTEXT: 'GETCONTEXT'}) - - const context = 'abc' - const engine = HyperFormula.buildFromArray([ - ['=GETCONTEXT()'], - ], {context}) - - expect(engine.getCellValue(adr('A1'))).toEqual(context) - }) -}) - -/** - * Mock plugin for testing handling of the depracated parameters. - */ -class DeprecatedPlugin extends FunctionPlugin { - public static implementedFunctions = { - FUNCTION_USING_ARRAY_FUNCTION_PARAM: { - method: 'implementation', - arrayFunction: true, - sizeOfResultArrayMethod: 'arraySizeMethod', - parameters: [ - { argumentType: FunctionArgumentType.NUMBER } - ], - }, - FUNCTION_USING_ARRAY_SIZE_METHOD_PARAM: { - method: 'implementation', - enableArrayArithmeticForArguments: true, - arraySizeMethod: 'arraySizeMethod', - parameters: [ - { argumentType: FunctionArgumentType.NUMBER } - ], - } - } - - public static translations = { - enGB: { - FUNCTION_USING_ARRAY_FUNCTION_PARAM: 'FUNCTION_USING_ARRAY_FUNCTION_PARAM', - FUNCTION_USING_ARRAY_SIZE_METHOD_PARAM: 'FUNCTION_USING_ARRAY_SIZE_METHOD_PARAM', - }, - enUS: { - FUNCTION_USING_ARRAY_FUNCTION_PARAM: 'FUNCTION_USING_ARRAY_FUNCTION_PARAM', - FUNCTION_USING_ARRAY_SIZE_METHOD_PARAM: 'FUNCTION_USING_ARRAY_SIZE_METHOD_PARAM', - }, - } - - /** - * Test function using deprecated arrayFunction parameter. - */ - implementation(ast: ProcedureAst, state: InterpreterState) { - return this.runFunction( - ast.args, - state, - this.metadata('FUNCTION_USING_ARRAY_FUNCTION_PARAM'), - (val: number) => { - return SimpleRangeValue.onlyValues([[val, val], [val, val]]) - }, - ) - } - - /** - * Returns array size for testing deprecated arrayFunction parameter. - */ - arraySizeMethod(): ArraySize { - return new ArraySize(2, 2) - } -} - -describe('Custum function using "arrayFunction" parameter', () => { - it('returns the correct result', () => { - HyperFormula.registerFunctionPlugin(DeprecatedPlugin, DeprecatedPlugin.translations) - const engine = HyperFormula.buildFromArray([['=FUNCTION_USING_ARRAY_FUNCTION_PARAM(1)']]) - - expect(engine.getSheetValues(0)).toEqual([[1, 1], [1, 1]]) - }) - - it('displays a deprecation warning in console', () => { - const consoleWarnSpy = spyOn(console, 'warn') - - try { - HyperFormula.registerFunctionPlugin(DeprecatedPlugin, DeprecatedPlugin.translations) - - expect(consoleWarnSpy).toHaveBeenCalledWith( - "FUNCTION_USING_ARRAY_FUNCTION_PARAM: 'arrayFunction' parameter is deprecated since 3.1.0; Use 'enableArrayArithmeticForArguments' instead." - ) - } finally { - resetSpy(consoleWarnSpy) - } - }) -}) - -describe('Custum function using "arraySizeMethod" parameter', () => { - it('returns the correct result', () => { - HyperFormula.registerFunctionPlugin(DeprecatedPlugin, DeprecatedPlugin.translations) - const engine = HyperFormula.buildFromArray([['=FUNCTION_USING_ARRAY_SIZE_METHOD_PARAM(1)']]) - - expect(engine.getSheetValues(0)).toEqual([[1, 1], [1, 1]]) - }) - - it('displays a deprecation warning in console', () => { - const consoleWarnSpy = spyOn(console, 'warn') - - try { - HyperFormula.registerFunctionPlugin(DeprecatedPlugin, DeprecatedPlugin.translations) - - expect(consoleWarnSpy).toHaveBeenCalledWith( - "FUNCTION_USING_ARRAY_SIZE_METHOD_PARAM: 'arraySizeMethod' parameter is deprecated since 3.1.0; Use 'sizeOfResultArrayMethod' instead." - ) - } finally { - resetSpy(consoleWarnSpy) - } - }) -}) diff --git a/test/unit/date.spec.ts b/test/unit/date.spec.ts deleted file mode 100644 index 44d1f25b78..0000000000 --- a/test/unit/date.spec.ts +++ /dev/null @@ -1,303 +0,0 @@ -import moment from 'moment' -import {Config} from '../../src/Config' -import {DateTimeHelper, SimpleDate} from '../../src/DateTimeHelper' -import {DateNumber, DateTimeNumber, getRawValue, TimeNumber} from '../../src/interpreter/InterpreterValue' -import {Maybe} from '../../src/Maybe' - -describe('Date helpers', () => { - it('#dateToNumber should return number representation of a date', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateToNumber({year: 1900, month: 1, day: 1})).toBe(2) - expect(dateHelper.dateToNumber({year: 1899, month: 12, day: 30})).toBe(0) - expect(dateHelper.dateToNumber({year: 1900, month: 12, day: 31})).toBe(366) - expect(dateHelper.dateToNumber({year: 2018, month: 12, day: 31})).toBe(43465) - }) - - it('#dateToNumber should return number representation of a date, excel compatibility', () => { - const dateHelper = new DateTimeHelper(new Config({leapYear1900: true, nullDate: { year:1899, month: 12, day: 31 }})) - expect(dateHelper.dateToNumber({year: 1899, month: 12, day: 31})).toBe(0) - expect(dateHelper.dateToNumber({year: 1900, month: 1, day: 1})).toBe(1) - expect(dateHelper.dateToNumber({year: 1900, month: 2, day: 28})).toBe(59) - expect(dateHelper.dateToNumber({year: 1900, month: 2, day: 29})).toBe(60) - expect(dateHelper.dateToNumber({year: 1900, month: 3, day: 1})).toBe(61) - expect(dateHelper.dateToNumber({year: 1900, month: 12, day: 31})).toBe(366) - expect(dateHelper.dateToNumber({year: 2018, month: 12, day: 31})).toBe(43465) - }) - - it('#dateNumberToMonthNumber should return proper month number', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.numberToSimpleDate(0).month).toEqual(12) - expect(dateHelper.numberToSimpleDate(2).month).toEqual(1) - expect(dateHelper.numberToSimpleDate(43465).month).toEqual(12) - }) - - it('#stringToDateNumber - tests expected to return not null, dates', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateStringToDateNumber('16/08/1985')).toEqual(new DateNumber(31275, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('15/01/2020')).toEqual(new DateNumber(43845, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('29/02/2000')).toEqual(new DateNumber(36585, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('31/12/2999')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('31 12 2999')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber(' 31 12 2999 ')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('31 12 2999')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - }) - - it('#stringToDateNumber - no time format', () => { - const dateHelper = new DateTimeHelper(new Config({timeFormats: []})) - expect(dateHelper.dateStringToDateNumber('16/08/1985')).toEqual(new DateNumber(31275, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('15/01/2020')).toEqual(new DateNumber(43845, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('29/02/2000')).toEqual(new DateNumber(36585, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('31/12/2999')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('31 12 2999')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber(' 31 12 2999 ')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('31 12 2999')).toEqual(new DateNumber(401768, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('16/08/1985 3:40')).toEqual(undefined) - }) - - it('#stringToDateNumber - tests expected to return not null, times', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateStringToDateNumber('00:00')).toEqual(new TimeNumber(0, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('03:00')).toEqual(new TimeNumber(0.125, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('24:00')).toEqual(new TimeNumber(1, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('48:00')).toEqual(new TimeNumber(2, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('00:01')).toEqual(new TimeNumber(0.0006944444444444445, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('00:00:00')).toEqual(new TimeNumber(0, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:00:00.001')).toEqual(new TimeNumber(1.1574074074074076e-8, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:00:00.0001')).toEqual(new TimeNumber(0, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:00:01')).toEqual(new TimeNumber(0.000011574074074074073, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:179:60')).toEqual(new TimeNumber(0.125, 'hh:mm:ss.sss')) - }) - - it('#stringToDateNumber - no date format', () => { - const dateHelper = new DateTimeHelper(new Config({dateFormats: []})) - expect(dateHelper.dateStringToDateNumber('00:00')).toEqual(new TimeNumber(0, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('03:00')).toEqual(new TimeNumber(0.125, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('24:00')).toEqual(new TimeNumber(1, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('48:00')).toEqual(new TimeNumber(2, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('00:01')).toEqual(new TimeNumber(0.0006944444444444445, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('00:00:00')).toEqual(new TimeNumber(0, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:00:00.001')).toEqual(new TimeNumber(1.1574074074074076e-8, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:00:00.0001')).toEqual(new TimeNumber(0, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:00:01')).toEqual(new TimeNumber(0.000011574074074074073, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('00:179:60')).toEqual(new TimeNumber(0.125, 'hh:mm:ss.sss')) - expect(dateHelper.dateStringToDateNumber('16/08/1985 3:40')).toEqual(undefined) - }) - - it('#stringToDateNumber - fraction of seconds', () => { - const dateHelper = new DateTimeHelper(new Config({timeFormats: ['hh:mm:ss.ss']})) - expect(getRawValue(dateHelper.dateStringToDateNumber('00:00:00.1'))).toBeCloseTo(0.0000011574074074074074) - expect(getRawValue(dateHelper.dateStringToDateNumber('00:00:00.01'))).toBeCloseTo(1.1574074074074073e-7) - expect(getRawValue(dateHelper.dateStringToDateNumber('00:00:00.001'))).toBeCloseTo(0) - }) - - it('#stringToDateNumber am/pm', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateStringToDateNumber('03:00 am')).toEqual(new TimeNumber(0.125, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('03:00 a')).toEqual(new TimeNumber(0.125, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('03:00 pm')).toEqual(new TimeNumber(0.625, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('12:00 pm')).toEqual(new TimeNumber(0.5, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('12:00 p')).toEqual(new TimeNumber(0.5, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('00:00 pm')).toEqual(new TimeNumber(0.5, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('12:59 pm')).toEqual(new TimeNumber(0.5409722222222222, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('12:00 am')).toEqual(new TimeNumber(0.0, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('00:00 am')).toEqual(new TimeNumber(0.0, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('12:59 am')).toEqual(new TimeNumber(0.04097222222222222, 'hh:mm')) - expect(dateHelper.dateStringToDateNumber('13:00 am')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('13:00 pm')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('pm')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('02/02/2020 pm')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('02/02/2020 12:00pm')).toEqual(new DateTimeNumber(43863.5, 'DD/MM/YYYY hh:mm')) - expect(dateHelper.dateStringToDateNumber('02/02/2020 12:9999pm')).toEqual(new DateTimeNumber(43870.44375, 'DD/MM/YYYY hh:mm')) - }) - - it('#stringToDateNumber - tests expected to return not null, dates + times', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateStringToDateNumber('16/08/1985 03:40')).toEqual(new DateTimeNumber(31275.152777777777, 'DD/MM/YYYY hh:mm')) - expect(dateHelper.dateStringToDateNumber(' 31 12 2999 00:00:00 ')).toEqual(new DateTimeNumber(401768, 'DD/MM/YYYY hh:mm:ss.sss')) - }) - - it('#stringToDateNumber - excel compatibility', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateStringToDateNumber('29/02/1900')).toBe(undefined) - const dateHelper2 = new DateTimeHelper(new Config({leapYear1900: true})) - expect(dateHelper2.dateStringToDateNumber('29/02/1900')).toEqual(new DateNumber(61, 'DD/MM/YYYY')) - }) - - it('stringToDateNumber - 00 year parsing', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateStringToDateNumber('16/08/85')).toEqual(new DateNumber(31275, 'DD/MM/YY')) - expect(dateHelper.dateStringToDateNumber('15/01/20')).toEqual(new DateNumber(43845, 'DD/MM/YY')) - expect(dateHelper.dateStringToDateNumber('29/02/00')).toEqual(new DateNumber(36585, 'DD/MM/YY')) - expect(dateHelper.dateStringToDateNumber('31/12/99')).toEqual(new DateNumber(36525, 'DD/MM/YY')) - const dateHelper1 = new DateTimeHelper(new Config({nullYear: 0})) - expect(dateHelper1.dateStringToDateNumber('15/01/20')).toEqual(new DateNumber(7320, 'DD/MM/YY')) - const dateHelper2 = new DateTimeHelper(new Config({nullYear: 100})) - expect(dateHelper2.dateStringToDateNumber('31/12/99')).toEqual(new DateNumber(73050, 'DD/MM/YY')) - }) - - it('stringToDateNumber - other date formats', () => { - const dateHelper = new DateTimeHelper(new Config({dateFormats: ['MM/DD/YYYY']})) - expect(dateHelper.dateStringToDateNumber('12/31/99')).toBe(undefined) - const dateHelper1 = new DateTimeHelper(new Config({dateFormats: ['YY/MM/DD']})) - expect(dateHelper1.dateStringToDateNumber('99/12/31')).toEqual(new DateNumber(36525, 'YY/MM/DD')) - const dateHelper2 = new DateTimeHelper(new Config({dateFormats: ['MM/DD/YY', 'YY/MM/DD']})) - expect(dateHelper2.dateStringToDateNumber('99/12/31')).toEqual(new DateNumber(36525, 'YY/MM/DD')) - const dateHelper3 = new DateTimeHelper(new Config({dateFormats: ['YYYY/DD/MM']})) - expect(dateHelper3.dateStringToDateNumber('1999/12/31')).toBe(undefined) - const dateHelper4 = new DateTimeHelper(new Config({dateFormats: ['YYYY/MM/DD']})) - expect(dateHelper4.dateStringToDateNumber('1999/12/31')).toEqual(new DateNumber(36525, 'YYYY/MM/DD')) - const dateHelper5 = new DateTimeHelper(new Config({dateFormats: ['MM/YYYY/DD']})) - expect(dateHelper5.dateStringToDateNumber('12/1999/31')).toEqual(new DateNumber(36525, 'MM/YYYY/DD')) - const dateHelper6 = new DateTimeHelper(new Config({dateFormats: ['DD/YYYY/MM']})) - expect(dateHelper6.dateStringToDateNumber('31/1999/12')).toEqual(new DateNumber(36525, 'DD/YYYY/MM')) - const dateHelper7 = new DateTimeHelper(new Config({dateFormats: ['DD/MM/YYYY']})) - expect(dateHelper7.dateStringToDateNumber('31/12/1999')).toEqual(new DateNumber(36525, 'DD/MM/YYYY')) - const dateHelper8 = new DateTimeHelper(new Config({dateFormats: ['YY/DD/MM']})) - expect(dateHelper8.dateStringToDateNumber('99/31/12')).toEqual(new DateNumber(36525, 'YY/DD/MM')) - const dateHelper9 = new DateTimeHelper(new Config({dateFormats: ['MM/YY/DD']})) - expect(dateHelper9.dateStringToDateNumber('12/99/31')).toEqual(new DateNumber(36525, 'MM/YY/DD')) - const dateHelper10 = new DateTimeHelper(new Config({dateFormats: ['DD/MM/YY']})) - expect(dateHelper10.dateStringToDateNumber('31/12/99')).toEqual(new DateNumber(36525, 'DD/MM/YY')) - const dateHelper11 = new DateTimeHelper(new Config({dateFormats: ['DD/YY/MM']})) - expect(dateHelper11.dateStringToDateNumber('31/99/12')).toEqual(new DateNumber(36525, 'DD/YY/MM')) - }) - - it('stringToDateNumber - other time formats', () => { - const dateHelper = new DateTimeHelper(new Config({timeFormats: ['mm:hh']})) - expect(dateHelper.dateStringToDateNumber('60:02')).toEqual(new TimeNumber(0.125, 'mm:hh')) - }) - - it('#stringToDateNumber - tests expected to return undefined', () => { - const dateHelper = new DateTimeHelper(new Config()) - expect(dateHelper.dateStringToDateNumber('1/1/10000')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('5/29/1453')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('www')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('0')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('0/0/1999')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('13/13/2020')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('w8')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('www1')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('10/2020')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('12//31/2999')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('12/31/2999 0')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('12//31/2999 0:0')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('12/31/2999 0:0:0:0')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('12:00 12/31/2999')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber(' ')).toBe(undefined) - expect(dateHelper.dateStringToDateNumber('')).toBe(undefined) - }) -}) - -describe('Date helpers, other zero date', () => { - it('#dateToNumber should return number representation of a date, different zero date', () => { - const dateHelper = new DateTimeHelper(new Config({nullDate: {year: 1950, month: 6, day: 15}})) - expect(dateHelper.dateToNumber({year: 1900, month: 1, day: 1})).toBe(-18427) - expect(dateHelper.dateToNumber({year: 1899, month: 12, day: 30})).toBe(-18429) - expect(dateHelper.dateToNumber({year: 1900, month: 12, day: 31})).toBe(-18063) - expect(dateHelper.dateToNumber({year: 2018, month: 12, day: 31})).toBe(25036) - }) - - it('#dateNumberToMonthNumber should return proper month number, different zero date', () => { - const config = new Config({nullDate: {year: 1950, month: 6, day: 15}}) - const dateHelper = new DateTimeHelper(config) - expect(dateHelper.numberToSimpleDate(0).month).toEqual(6) - expect(dateHelper.numberToSimpleDate(2).month).toEqual(6) - expect(dateHelper.numberToSimpleDate(43465).month).toEqual(6) - }) - - it('#stringToDateNumber - tests expected to return not null, different zero date', () => { - const dateHelper = new DateTimeHelper(new Config({nullDate: {year: 1950, month: 6, day: 15}})) - expect(dateHelper.dateStringToDateNumber('16/08/1985')).toEqual(new DateNumber(12846, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('15/01/2020')).toEqual(new DateNumber(25416, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('29/02/2000')).toEqual(new DateNumber(18156, 'DD/MM/YYYY')) - expect(dateHelper.dateStringToDateNumber('31/12/2999')).toEqual(new DateNumber(383339, 'DD/MM/YYYY')) - }) -}) - -describe('By default function parseDateTimeFromConfigFormats', () => { - it('returns {} when dateFormats=[] and timeFormats=[]', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: [], timeFormats: [] })) - const parsedDate = dateHelper.parseDateTimeFromConfigFormats('01/01/2019') - expect(parsedDate).toEqual({}) - }) - - it('returns {} when trying to parse date but dateFormats=[]', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: [] })) - const parsedDate = dateHelper.parseDateTimeFromConfigFormats('01/01/2019') - expect(parsedDate).toEqual({}) - }) - - it('returns {} when trying to parse time but timeFormats=[]', () => { - const dateHelper = new DateTimeHelper(new Config({ timeFormats: [] })) - const parsedDate = dateHelper.parseDateTimeFromConfigFormats('01:01') - expect(parsedDate).toEqual({}) - }) - - it('returns {} when time format contains no day term', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: ['MM/YY'] })) - const parsedDate = dateHelper.parseDateTimeFromConfigFormats('12/12') - expect(parsedDate).toEqual({}) - }) - - it('returns {} when time format contains no month term', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: ['DD/YY'] })) - const parsedDate = dateHelper.parseDateTimeFromConfigFormats('12/12') - expect(parsedDate).toEqual({}) - }) - - it('returns {} when time format contains no year term', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: ['DD/MM'] })) - const parsedDate = dateHelper.parseDateTimeFromConfigFormats('12/12') - expect(parsedDate).toEqual({}) - }) - - it('returns {} when time format contains both long year and short year term', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: ['DD/MM/YY/YYYY'] })) - const parsedDate = dateHelper.parseDateTimeFromConfigFormats('12/12/12/12') - expect(parsedDate).toEqual({}) - }) - - it('parses a time value with AM/PM postfix', () => { - const dateHelper = new DateTimeHelper(new Config({ timeFormats: ['hh:mm am/pm'] })) - const { dateTime: dateTimeWithPrefix } = dateHelper.parseDateTimeFromConfigFormats('01:01 pm') - const { dateTime: dateTimeWithOutPrefix } = dateHelper.parseDateTimeFromConfigFormats('13:01') - expect(dateTimeWithPrefix).toEqual(dateTimeWithOutPrefix) - }) - - it('parses a time value with A/P postfix', () => { - const dateHelper = new DateTimeHelper(new Config({ timeFormats: ['hh:mm a/p'] })) - const { dateTime: dateTimeWithPrefix } = dateHelper.parseDateTimeFromConfigFormats('01:01 p') - const { dateTime: dateTimeWithOutPrefix } = dateHelper.parseDateTimeFromConfigFormats('13:01') - expect(dateTimeWithPrefix).toEqual(dateTimeWithOutPrefix) - }) - - it('returns the matching dateFormat', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: ['DD/MM/YY', 'DD/MM/YYYY'], timeFormats: ['hh:mm:ss', 'hh:mm'] })) - const { dateFormat } = dateHelper.parseDateTimeFromConfigFormats('01/01/2019') - expect(dateFormat).toEqual('DD/MM/YYYY') - }) - - it('returns the matching timeFormat', () => { - const dateHelper = new DateTimeHelper(new Config({ dateFormats: ['DD/MM/YY', 'DD/MM/YYYY'], timeFormats: ['hh:mm:ss', 'hh:mm'] })) - const { timeFormat } = dateHelper.parseDateTimeFromConfigFormats('01:01') - expect(timeFormat).toEqual('hh:mm') - }) -}) - -describe('Custom date parsing', () => { - function customParseDate(dateString: string, dateFormat?: string): Maybe { - const momentDate = moment(dateString, dateFormat, true) - if (momentDate.isValid()) { - return {year: momentDate.year(), month: momentDate.month() + 1, day: momentDate.date()} - } - return undefined - } - - it('moment-based custom parsing', () => { - const config = new Config({parseDateTime: customParseDate, dateFormats: ['Do MMM YY', 'DDD YYYY']}) - const dateHelper = new DateTimeHelper(config) - expect(dateHelper.dateStringToDateNumber('31st Jan 00')).toEqual(new DateNumber(36556, 'Do MMM YY')) - expect(dateHelper.dateStringToDateNumber('365 1900')).toEqual(new DateNumber(366, 'DDD YYYY')) - }) -}) diff --git a/test/unit/dependency-graph-sheet-reference-registrar.spec.ts b/test/unit/dependency-graph-sheet-reference-registrar.spec.ts deleted file mode 100644 index 1fe440d6a5..0000000000 --- a/test/unit/dependency-graph-sheet-reference-registrar.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { AlwaysDense } from '../../src' -import {AddressMapping, DenseStrategy, SheetMapping, SheetReferenceRegistrar} from '../../src/DependencyGraph' -import {buildTranslationPackage} from '../../src/i18n' -import {enGB} from '../../src/i18n/languages' - -describe('SheetReferenceRegistrar', () => { - const createDependencies = () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - const addressMapping = new AddressMapping(new AlwaysDense()) - const registrar = new SheetReferenceRegistrar(sheetMapping, addressMapping) - return { sheetMapping, addressMapping, registrar } - } - - it('when called with non-existing sheet, adds a placeholder', () => { - const { sheetMapping, addressMapping, registrar } = createDependencies() - - const sheetId = registrar.ensureSheetRegistered('NewSheet') - - expect(sheetMapping.numberOfSheets({ includePlaceholders: true })).toBe(1) - expect(sheetMapping.hasSheetWithId(sheetId, { includePlaceholders: true })).toBe(true) - expect(() => addressMapping.getStrategyForSheetOrThrow(sheetId)).not.toThrow() - }) - - it('when called with existing placeholder sheet, doesnt modify address mapping nor sheet mapping', () => { - const { sheetMapping, addressMapping, registrar } = createDependencies() - const firstSheetId = registrar.ensureSheetRegistered('PlaceholderSheet') - - const secondSheetId = registrar.ensureSheetRegistered('PlaceholderSheet') - - expect(secondSheetId).toBe(firstSheetId) - expect(sheetMapping.numberOfSheets({ includePlaceholders: true })).toBe(1) - expect(() => addressMapping.getStrategyForSheetOrThrow(firstSheetId)).not.toThrow() - }) - - it('when called with existing real sheet, doesnt modify address mapping nor sheet mapping', () => { - const { sheetMapping, addressMapping, registrar } = createDependencies() - const realSheetId = sheetMapping.addSheet('RealSheet') - addressMapping.addSheetWithStrategy(realSheetId, new DenseStrategy(0, 0)) - - const returnedSheetId = registrar.ensureSheetRegistered('RealSheet') - - expect(returnedSheetId).toBe(realSheetId) - expect(sheetMapping.numberOfSheets({ includePlaceholders: true })).toBe(1) - expect(sheetMapping.numberOfSheets({ includePlaceholders: false })).toBe(1) - expect(() => addressMapping.getStrategyForSheetOrThrow(realSheetId)).not.toThrow() - }) - - it('when called with name that differs from some placeholder sheet only by case, doesnt modify address mapping nor sheet mapping', () => { - const { sheetMapping, addressMapping, registrar } = createDependencies() - const firstSheetId = registrar.ensureSheetRegistered('PlaceholderSheet') - - const secondSheetId = registrar.ensureSheetRegistered('PLACEHOLDERSHEET') - - expect(secondSheetId).toBe(firstSheetId) - expect(secondSheetId).toBe(firstSheetId) - expect(sheetMapping.numberOfSheets({ includePlaceholders: true })).toBe(1) - expect(() => addressMapping.getStrategyForSheetOrThrow(firstSheetId)).not.toThrow() - }) - - it('when called with name that differs from some real sheet only by case, doesnt modify address mapping nor sheet mapping', () => { - const { sheetMapping, addressMapping, registrar } = createDependencies() - const realSheetId = sheetMapping.addSheet('RealSheet') - addressMapping.addSheetWithStrategy(realSheetId, new DenseStrategy(0, 0)) - - const returnedSheetId = registrar.ensureSheetRegistered('REALSHEET') - - expect(returnedSheetId).toBe(realSheetId) - expect(sheetMapping.numberOfSheets({ includePlaceholders: true })).toBe(1) - expect(sheetMapping.numberOfSheets({ includePlaceholders: false })).toBe(1) - expect(() => addressMapping.getStrategyForSheetOrThrow(realSheetId)).not.toThrow() - }) -}) diff --git a/test/unit/dependencyTransformers/clean-out-of-scope-dependencies-transformer.spec.ts b/test/unit/dependencyTransformers/clean-out-of-scope-dependencies-transformer.spec.ts deleted file mode 100644 index 2fc4393ee5..0000000000 --- a/test/unit/dependencyTransformers/clean-out-of-scope-dependencies-transformer.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { CleanOutOfScopeDependenciesTransformer } from '../../../src/dependencyTransformers/CleanOutOfScopeDependenciesTransformer' - -describe('CleanOutOfScopeDependenciesTransformer', () => { - - it('isIrreversible always returns true', () => { - const transformer = new CleanOutOfScopeDependenciesTransformer(5) - expect(transformer.isIrreversible()).toEqual(true) - }) - -}) diff --git a/test/unit/dependencyTransformers/combined-transformer.spec.ts b/test/unit/dependencyTransformers/combined-transformer.spec.ts deleted file mode 100644 index d0afcdded9..0000000000 --- a/test/unit/dependencyTransformers/combined-transformer.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { adr } from '../testUtils' -import { Config } from '../../../src/Config' -import { CombinedTransformer } from '../../../src/dependencyTransformers/CombinedTransformer' -import { HyperFormula } from '../../../src' -import { buildEmptyParserWithCaching } from '../parser/common' -import { AbsoluteCellRange } from '../../../src/AbsoluteCellRange' - -describe('CombinedTransformer', () => { - - it('performEagerTransformations() coverage', () => { - const transformer = new CombinedTransformer(0) - const parser = buildEmptyParserWithCaching(new Config()) - - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'] - ]) - - transformer.performEagerTransformations(engine.dependencyGraph, parser) - - expect(engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2))).toEqual([ - [1, 2], - [3, 4], - ]) - - expect(transformer.isIrreversible()).toEqual(true) - }) - -}) diff --git a/test/unit/dependencyTransformers/remove-columns-transformer.spec.ts b/test/unit/dependencyTransformers/remove-columns-transformer.spec.ts deleted file mode 100644 index aceea687e3..0000000000 --- a/test/unit/dependencyTransformers/remove-columns-transformer.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { simpleCellAddress } from '../../../src/Cell' -import { Config } from '../../../src/Config' -import { CellRangeAst } from '../../../src/parser' -import { buildEmptyParserWithCaching } from '../parser/common' -import { adr } from '../testUtils' -import { ParenthesisAst, ProcedureAst } from '../../../src/parser/Ast' -import { ColumnsSpan } from '../../../src/Span' -import { RemoveColumnsTransformer } from '../../../src/dependencyTransformers/RemoveColumnsTransformer' - -describe('RemoveColumnsTransformer', () => { - - it('transformColRange error - removing cols from left of range throws error', () => { - const transformer = new RemoveColumnsTransformer(new ColumnsSpan(0, 5, 5)) - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=(SUM(C2:F7))', adr('A1', 1)).ast - - { - const astParen = ast as ParenthesisAst - const astSum = astParen.expression as ProcedureAst - const astSumArg = astSum.args[0] as CellRangeAst - expect(astSumArg.start.sheet).toBeUndefined() - expect(astSumArg.start.col).toEqual(2) - expect(astSumArg.start.row).toEqual(1) - expect(astSumArg.end.sheet).toBeUndefined() - expect(astSumArg.end.col).toEqual(5) - expect(astSumArg.end.row).toEqual(6) - } - - expect(() => { - transformer.transformSingleAst(ast, simpleCellAddress(0, 5, 5)) - }).toThrowError('Cannot happen') - - }) - -}) diff --git a/test/unit/dependencyTransformers/remove-rows-transformer.spec.ts b/test/unit/dependencyTransformers/remove-rows-transformer.spec.ts deleted file mode 100644 index 94a56f703b..0000000000 --- a/test/unit/dependencyTransformers/remove-rows-transformer.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { ErrorType, simpleCellAddress } from '../../../src/Cell' -import { Config } from '../../../src/Config' -import { CellRangeAst } from '../../../src/parser' -import { buildEmptyParserWithCaching } from '../parser/common' -import { adr } from '../testUtils' -import { ParenthesisAst, ProcedureAst, ErrorAst } from '../../../src/parser/Ast' -import { RowsSpan } from '../../../src/Span' -import { RemoveRowsTransformer } from '../../../src/dependencyTransformers/RemoveRowsTransformer' - -describe('RemoveRowsTransformer', () => { - - it('transformRowRange error - removing rows from top of range', () => { - const transformer = new RemoveRowsTransformer(new RowsSpan(0, 0, 2)) - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=(SUM(C2:F7))', adr('A1', 1)).ast - - { - const astParen = ast as ParenthesisAst - const astSum = astParen.expression as ProcedureAst - const astSumArg = astSum.args[0] as CellRangeAst - expect(astSumArg.start.sheet).toBeUndefined() - expect(astSumArg.start.col).toEqual(2) - expect(astSumArg.start.row).toEqual(1) - expect(astSumArg.end.sheet).toBeUndefined() - expect(astSumArg.end.col).toEqual(5) - expect(astSumArg.end.row).toEqual(6) - } - - const [transformedAst, cellAddress] = transformer.transformSingleAst(ast, simpleCellAddress(0, 0, 0)) - - { - const astParen = transformedAst as ParenthesisAst - const astSum = astParen.expression as ProcedureAst - const astSumError = astSum.args[0] as ErrorAst - expect(astSumError.type).toEqual(ErrorType.ERROR) - expect(astSumError.error.type).toEqual(ErrorType.REF) - expect(cellAddress.sheet).toEqual(0) - expect(cellAddress.col).toEqual(0) - expect(cellAddress.row).toEqual(-3) - } - - }) - -}) diff --git a/test/unit/dependencyTransformers/transformer.spec.ts b/test/unit/dependencyTransformers/transformer.spec.ts deleted file mode 100644 index 4c93e406ac..0000000000 --- a/test/unit/dependencyTransformers/transformer.spec.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { ErrorType, simpleCellAddress, SimpleCellAddress } from '../../../src/Cell' -import { Config } from '../../../src/Config' -import { CellAddress, CellRangeAst } from '../../../src/parser' -import { ColumnAddress } from '../../../src/parser/ColumnAddress' -import { RowAddress } from '../../../src/parser/RowAddress' -import { Transformer } from '../../../src/dependencyTransformers/Transformer' -import { buildEmptyParserWithCaching } from '../parser/common' -import { adr } from '../testUtils' -import { ParenthesisAst, ProcedureAst, ArrayAst } from '../../../src/parser/Ast' - -describe('Transformer', () => { - - /** - * A mock Transformer subclass that can be used to test the methods implemented in the partially abstract Transform class - */ - class MockTransformer extends Transformer { - constructor() { - super() - } - public get sheet(): number { - return 0 - } - public isIrreversible(): boolean { - return false - } - protected transformCellAddress(dependencyAddress: T, formulaAddress: SimpleCellAddress): T | ErrorType.REF | false { - return ErrorType.REF - } - protected transformCellRange(start: CellAddress, end: CellAddress, formulaAddress: SimpleCellAddress): [CellAddress, CellAddress] | ErrorType.REF | false { - const newStart = new CellAddress(15, 10, start.type, 19) - const newEnd = new CellAddress(20, 30, start.type, 19) - return [newStart, newEnd] - } - protected transformRowRange(start: RowAddress, end: RowAddress, formulaAddress: SimpleCellAddress): [RowAddress, RowAddress] | ErrorType.REF | false { - return ErrorType.REF - } - protected transformColumnRange(start: ColumnAddress, end: ColumnAddress, formulaAddress: SimpleCellAddress): [ColumnAddress, ColumnAddress] | ErrorType.REF | false { - return ErrorType.REF - } - protected fixNodeAddress(address: SimpleCellAddress): SimpleCellAddress { - return simpleCellAddress(19, 12, 50) - } - } - - it('transformSingleAst - type PARENTHESIS', () => { - const transformer = new MockTransformer() - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=(SUM(C2:F7))', adr('A1')).ast - - { - const astParen = ast as ParenthesisAst - const astSum = astParen.expression as ProcedureAst - const astSumArg = astSum.args[0] as CellRangeAst - expect(astSumArg.start.sheet).toBeUndefined() - expect(astSumArg.start.col).toEqual(2) - expect(astSumArg.start.row).toEqual(1) - expect(astSumArg.end.sheet).toBeUndefined() - expect(astSumArg.end.col).toEqual(5) - expect(astSumArg.end.row).toEqual(6) - } - - const [transformedAst, cellAddress] = transformer.transformSingleAst(ast, simpleCellAddress(0, 2, 2)) - - { - const astParen = transformedAst as ParenthesisAst - const astSum = astParen.expression as ProcedureAst - const astSumArg = astSum.args[0] as CellRangeAst - expect(astSumArg.start.sheet).toEqual(19) - expect(astSumArg.start.col).toEqual(15) - expect(astSumArg.start.row).toEqual(10) - expect(astSumArg.end.sheet).toEqual(19) - expect(astSumArg.end.col).toEqual(20) - expect(astSumArg.end.row).toEqual(30) - expect(cellAddress.sheet).toEqual(19) - expect(cellAddress.col).toEqual(12) - expect(cellAddress.row).toEqual(50) - } - - }) - - it('transformSingleAst - type ARRAY', () => { - const transformer = new MockTransformer() - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('={SUM(C2:F7)}', adr('A1')).ast - - { - const astArray = ast as ArrayAst - const astSum = astArray.args[0][0] as ProcedureAst - const astSumArg = astSum.args[0] as CellRangeAst - expect(astSumArg.start.sheet).toBeUndefined() - expect(astSumArg.start.col).toEqual(2) - expect(astSumArg.start.row).toEqual(1) - expect(astSumArg.end.sheet).toBeUndefined() - expect(astSumArg.end.col).toEqual(5) - expect(astSumArg.end.row).toEqual(6) - } - - const [transformedAst, cellAddress] = transformer.transformSingleAst(ast, simpleCellAddress(0, 2, 2)) - - { - const astArray = transformedAst as ArrayAst - const astSum = astArray.args[0][0] as ProcedureAst - const astSumArg = astSum.args[0] as CellRangeAst - expect(astSumArg.start.sheet).toEqual(19) - expect(astSumArg.start.col).toEqual(15) - expect(astSumArg.start.row).toEqual(10) - expect(astSumArg.end.sheet).toEqual(19) - expect(astSumArg.end.col).toEqual(20) - expect(astSumArg.end.row).toEqual(30) - expect(cellAddress.sheet).toEqual(19) - expect(cellAddress.col).toEqual(12) - expect(cellAddress.row).toEqual(50) - } - - }) - -}) diff --git a/test/unit/dependent-formula-transformer.spec.ts b/test/unit/dependent-formula-transformer.spec.ts deleted file mode 100644 index be1e59b970..0000000000 --- a/test/unit/dependent-formula-transformer.spec.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {adr} from './testUtils' -import {DependentFormulaTransformer} from '../../src/dependencyTransformers/MoveCellsTransformer' - -describe('DependentFormulaTransformer', () => { - it('basic functionality', () => { - const sheetId = 99 - const sourceRange = AbsoluteCellRange.spanFrom(adr('A1', sheetId), 1, 1) - const transformer = new DependentFormulaTransformer(sourceRange, 1, 1, 0) - - expect(transformer.sheet).toBe(sheetId) - expect(transformer.isIrreversible()).toBe(true) - }) -}) diff --git a/test/unit/destruct.spec.ts b/test/unit/destruct.spec.ts deleted file mode 100644 index 13db9dcfbb..0000000000 --- a/test/unit/destruct.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {HyperFormula} from '../../src' - -describe('engine destruct', () => { - it('should throw exception after destruct', () => { - const engine = HyperFormula.buildEmpty() - engine.destroy() - expect(() => engine.getConfig()).toThrow() - }) - - it('should have keys removed', () => { - const engine = HyperFormula.buildEmpty() - engine.destroy() - expect(engine?.dependencyGraph).toBeUndefined() - }) - - it('should not affect other instances', () => { - const engine1 = HyperFormula.buildEmpty() - const engine2 = HyperFormula.buildEmpty() - engine1.destroy() - const engine3 = HyperFormula.buildEmpty() - expect(() => engine2.getConfig()).not.toThrow() - expect(() => engine3.getConfig()).not.toThrow() - }) - - it('should not affect static methods', () => { - const engine1 = HyperFormula.buildEmpty() - engine1.destroy() - expect(() => HyperFormula.getAllFunctionPlugins()).not.toThrow() - }) -}) diff --git a/test/unit/emitting-events.spec.ts b/test/unit/emitting-events.spec.ts deleted file mode 100644 index 6db2665da3..0000000000 --- a/test/unit/emitting-events.spec.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { - ExportedCellChange, - ExportedNamedExpressionChange, - HyperFormula, - ErrorType, - NamedExpressionDoesNotExistError, -} from '../../src' -import {Events} from '../../src/Emitter' -import { ErrorMessage } from '../../src/error-message' - -import {adr, detailedErrorWithOrigin} from './testUtils' - -describe('Events', () => { - it('sheetAdded works', function() { - const engine = HyperFormula.buildEmpty() - const handler = jasmine.createSpy() - - engine.on(Events.SheetAdded, handler) - engine.addSheet('FooBar') - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith('FooBar') - }) - - it('sheetRemoved works', function() { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['=Sheet2!A1']], - Sheet2: [['42']], - }) - const handler = jasmine.createSpy() - - engine.on(Events.SheetRemoved, handler) - engine.removeSheet(1) - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith('Sheet2', [new ExportedCellChange(adr('A1'), detailedErrorWithOrigin(ErrorType.REF, 'Sheet1!A1', ErrorMessage.SheetRef))]) - }) - - it('sheetRemoved name contains actual display name', function() { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['=Sheet2!A1']], - Sheet2: [['42']], - }) - const handler = jasmine.createSpy() - - engine.on(Events.SheetRemoved, handler) - engine.removeSheet(1) - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith('Sheet2', [new ExportedCellChange(adr('A1'), detailedErrorWithOrigin(ErrorType.REF, 'Sheet1!A1', ErrorMessage.SheetRef))]) - }) - - it('sheetRenamed works', () => { - const engine = HyperFormula.buildFromArray([[]]) - const handler = jasmine.createSpy() - - engine.on(Events.SheetRenamed, handler) - engine.renameSheet(0, 'SomeNewName') - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith('Sheet1', 'SomeNewName') - }) - - it('sheetRenamed is not triggered when sheet didnt change', () => { - const engine = HyperFormula.buildFromArray([[]]) - const handler = jasmine.createSpy() - - engine.on(Events.SheetRenamed, handler) - engine.renameSheet(0, 'Sheet1') - - expect(handler).not.toHaveBeenCalled() - }) - - it('namedExpressionAdded works', () => { - const engine = HyperFormula.buildEmpty() - const handler = jasmine.createSpy() - - engine.on(Events.NamedExpressionAdded, handler) - engine.addNamedExpression('myName', 'foobarbaz') - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith('myName', [new ExportedNamedExpressionChange('myName', 'foobarbaz')]) - }) - - it('namedExpressionRemoved works', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('myName', 'foobarbaz') - const handler = jasmine.createSpy() - - engine.on(Events.NamedExpressionRemoved, handler) - engine.removeNamedExpression('myName') - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith('myName', []) - }) - - it('namedExpressionRemoved throws error when named expression not exists', () => { - const engine = HyperFormula.buildEmpty() - const handler = jasmine.createSpy() - - engine.on(Events.NamedExpressionRemoved, handler) - expect(() => { - engine.removeNamedExpression('myName') - }).toThrow(new NamedExpressionDoesNotExistError('myName')) - }) - - it('namedExpressionRemoved contains an actual named-expression name', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('myName', 'foobarbaz') - const handler = jasmine.createSpy() - - engine.on(Events.NamedExpressionRemoved, handler) - engine.removeNamedExpression('MYNAME') - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith('myName', []) - }) - - it('valuesUpdated works', () => { - const engine = HyperFormula.buildFromArray([ - ['42'] - ]) - const handler = jasmine.createSpy() - - engine.on(Events.ValuesUpdated, handler) - engine.setCellContents(adr('A1'), [['43']]) - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith([new ExportedCellChange(adr('A1'), 43)]) - }) - - it('valuesUpdated works with named expressions', () => { - const engine = HyperFormula.buildFromArray( - [['42']], - {}, - [{ name: 'NAMED_EXPR', expression: '=Sheet1!$A$1' }] - ) - const handler = jasmine.createSpy() - - engine.on(Events.ValuesUpdated, handler) - engine.setCellContents(adr('A1'), [['43']]) - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith([ - new ExportedCellChange(adr('A1'), 43), - new ExportedNamedExpressionChange('NAMED_EXPR', 43), - ]) - }) - - it('valuesUpdated may sometimes be triggered even if nothing changed', () => { - const engine = HyperFormula.buildFromArray([ - ['42'] - ]) - const handler = jasmine.createSpy() - - engine.on(Events.ValuesUpdated, handler) - engine.setCellContents(adr('A1'), [['42']]) - - expect(handler).toHaveBeenCalledTimes(1) - expect(handler).toHaveBeenCalledWith([new ExportedCellChange(adr('A1'), 42)]) - }) - - it('suspension and resuming of evaluation', () => { - const engine = HyperFormula.buildFromArray([ - ['42'] - ]) - const handlerUpdated = jasmine.createSpy() - const handlerSuspended = jasmine.createSpy() - const handlerResumed = jasmine.createSpy() - - engine.on(Events.ValuesUpdated, handlerUpdated) - engine.on(Events.EvaluationSuspended, handlerSuspended) - engine.on(Events.EvaluationResumed, handlerResumed) - - engine.suspendEvaluation() - expect(handlerUpdated).not.toHaveBeenCalled() - expect(handlerSuspended).toHaveBeenCalledTimes(1) - expect(handlerResumed).not.toHaveBeenCalled() - - engine.setCellContents(adr('A1'), [['13']]) - expect(handlerUpdated).not.toHaveBeenCalled() - expect(handlerSuspended).toHaveBeenCalledTimes(1) - expect(handlerResumed).not.toHaveBeenCalled() - - engine.resumeEvaluation() - expect(handlerUpdated).toHaveBeenCalledTimes(1) - expect(handlerSuspended).toHaveBeenCalledTimes(1) - expect(handlerResumed).toHaveBeenCalledTimes(1) - expect(handlerResumed).toHaveBeenCalledWith([new ExportedCellChange(adr('A1'), 13)]) - }) - - it('batching', () => { - const engine = HyperFormula.buildFromArray([ - ['42'] - ]) - const handlerUpdated = jasmine.createSpy() - const handlerSuspended = jasmine.createSpy() - const handlerResumed = jasmine.createSpy() - - engine.on(Events.ValuesUpdated, handlerUpdated) - engine.on(Events.EvaluationSuspended, handlerSuspended) - engine.on(Events.EvaluationResumed, handlerResumed) - - engine.batch(() => engine.setCellContents(adr('A1'), [['13']])) - expect(handlerUpdated).toHaveBeenCalledTimes(1) - expect(handlerSuspended).toHaveBeenCalledTimes(1) - expect(handlerResumed).toHaveBeenCalledTimes(1) - expect(handlerResumed).toHaveBeenCalledWith([new ExportedCellChange(adr('A1'), 13)]) - }) -}) - -describe('Subscribing only once', () => { - it('works', function() { - const engine = HyperFormula.buildEmpty() - const handler = jasmine.createSpy() - - engine.once(Events.SheetAdded, handler) - engine.addSheet('FooBar1') - engine.addSheet('FooBar2') - - expect(handler).toHaveBeenCalledTimes(1) - }) -}) - -describe('Unsubscribing', () => { - it('works', function() { - const engine = HyperFormula.buildEmpty() - const handler = jasmine.createSpy() - engine.on(Events.SheetAdded, handler) - engine.addSheet('FooBar1') - - engine.off(Events.SheetAdded, handler) - engine.addSheet('FooBar2') - - expect(handler).toHaveBeenCalledTimes(1) - }) -}) diff --git a/test/unit/engine.spec.ts b/test/unit/engine.spec.ts deleted file mode 100644 index cc3464d02a..0000000000 --- a/test/unit/engine.spec.ts +++ /dev/null @@ -1,1252 +0,0 @@ -import {DetailedCellError, ErrorType, HyperFormula, CellType, CellValueDetailedType, CellValueType, SimpleCellAddress, SimpleCellRange, ExpectedValueOfTypeError} from '../../src' -import {AbsoluteCellRange, simpleCellRange} from '../../src/AbsoluteCellRange' -import {Config} from '../../src/Config' -import {ErrorMessage} from '../../src/error-message' -import {plPL} from '../../src/i18n/languages' -import {adr, detailedError, expectArrayWithSameContent} from './testUtils' -import {simpleCellAddress} from '../../src/Cell' - -describe('#buildFromArray', () => { - it('load single value', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('load simple sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ]) - - expect(engine.getCellValue(adr('C2'))).toBe(6) - }) - - it('evaluate empty vertex', () => { - const engine = HyperFormula.buildFromArray([['=A5']]) - - expect(engine.getCellValue(adr('A5'))).toBe(null) - expect(engine.getCellValue(adr('A1'))).toBe(null) - }) - - it('evaluate empty vertex reference', () => { - const engine = HyperFormula.buildFromArray([[null, '=A1']]) - - expect(engine.getCellValue(adr('B1'))).toBe(null) - }) - - it('cycle', () => { - const engine = HyperFormula.buildFromArray([['=B1', '=C1', '=A1']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) - - it('cycle with formula', () => { - const engine = HyperFormula.buildFromArray([['5', '=A1+B1']]) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) - - it('operator precedence', () => { - const engine = HyperFormula.buildFromArray([['=3*7*2-4*1+2']]) - expect(engine.getCellValue(adr('A1'))).toBe(40) - }) - - it('operator precedence and brackets', () => { - const engine = HyperFormula.buildFromArray([['=3*7+((2-4)*(1+2)+3)*2']]) - expect(engine.getCellValue(adr('A1'))).toBe(15) - }) - - it('operator precedence with cells', () => { - const engine = HyperFormula.buildFromArray([['3', '4', '=B1*2+A1']]) - expect(engine.getCellValue(adr('C1'))).toBe(11) - }) - - it('parsing error', () => { - const engine = HyperFormula.buildFromArray([['=1A1']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('dependency before value', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '1', '2'], - ['=SUM(B2:C2)', '1', '2'], - ]) - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(3) - }) - - it('should handle different input types', () => { - const engine = HyperFormula.buildFromArray([['', null, undefined, 1, true]]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('B1'))).toBe(null) - expect(engine.getCellValue(adr('C1'))).toBe(null) - expect(engine.getCellValue(adr('D1'))).toBe(1) - expect(engine.getCellValue(adr('E1'))).toBe(true) - }) - - it('should work with other numerals', () => { - const engine = HyperFormula.buildFromArray([ - [0o777, 0xFF, 0b1010, 1_000_000_000_000], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(511) - expect(engine.getCellValue(adr('B1'))).toBe(255) - expect(engine.getCellValue(adr('C1'))).toBe(10) - expect(engine.getCellValue(adr('D1'))).toBe(1000000000000) - }) - - it('should be possible to build graph with reference to not existing sheet', () => { - const engine = HyperFormula.buildFromArray([['=Sheet2!A2']]) - - expect(engine.getCellFormula(adr('A1'))).toEqual('=Sheet2!A2') - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should propagate parsing errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(', '=A1'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellFormula(adr('A1'))).toEqual('=SUM(') - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellFormula(adr('B1'))).toEqual('=A1') - }) -}) - -describe('#getCellHyperlink', () => { - it('returns hyperlink url when present', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const engine = HyperFormula.buildFromArray([[`=HYPERLINK("${url}","${linkLabel}")`]]) - expect(engine.getCellHyperlink(adr('A1'))).toEqual(url) - }) - - it('returns undefined when url not present', () => { - const engine = HyperFormula.buildFromArray([['=HYPERLINK()', '5', 's1', null]]) - expect(engine.getCellHyperlink(adr('A1'))).toEqual(undefined) - expect(engine.getCellHyperlink(adr('B1'))).toEqual(undefined) - expect(engine.getCellHyperlink(adr('C1'))).toEqual(undefined) - expect(engine.getCellHyperlink(adr('D1'))).toEqual(undefined) - }) - - it('returns undefined when HYPERLINK not the root expression', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const prefix = 'Prefix: ' - const engine = HyperFormula.buildFromArray([[`=CONCATENATE("${prefix}",HYPERLINK("${url}","${linkLabel}"))`]]) - expect(engine.getCellHyperlink(adr('A1'))).toEqual(undefined) - }) - - it('returns hyperlink when HYPERLINK does not use strings directly', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const engine = HyperFormula.buildFromArray([[url, linkLabel, '=HYPERLINK(A1,B1)']]) - expect(engine.getCellHyperlink(adr('C1'))).toEqual(url) - }) - - it('returns hyperlink when HYPERLINK uses complex params', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const engine = HyperFormula.buildFromArray([[url, linkLabel, '=HYPERLINK(INDEX(A:A,ROW()),B1)']]) - expect(engine.getCellHyperlink(adr('C1'))).toEqual(url) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - engine.getCellHyperlink({} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#getCellFormula', () => { - it('returns formula when present', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1,2,3,C3)'], - ]) - - expect(engine.getCellFormula(adr('A1'))).toEqual('=SUM(1,2,3,C3)') - }) - - it('works with -0', () => { - const engine = HyperFormula.buildFromArray([ - ['=-0'], - ]) - - expect(engine.getCellFormula(adr('A1'))).toEqual('=-0') - }) - - it('returns undefined for simple values', () => { - const engine = HyperFormula.buildFromArray([ - [''], - ['42'], - ['foobar'], - ]) - - expect(engine.getCellFormula(adr('A1'))).toEqual(undefined) - expect(engine.getCellFormula(adr('A2'))).toEqual(undefined) - expect(engine.getCellFormula(adr('A3'))).toEqual(undefined) - expect(engine.getCellFormula(adr('A4'))).toEqual(undefined) - }) - - it('returns matrix formula for matrix vertices', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['1', '1'], - ['=MMULT(A1:B2,A1:B2)'], - ]) - - expect(engine.getCellFormula(adr('A3'))).toEqual('=MMULT(A1:B2,A1:B2)') - expect(engine.getCellFormula(adr('A4'))).toEqual(undefined) - expect(engine.getCellFormula(adr('B3'))).toEqual(undefined) - expect(engine.getCellFormula(adr('B4'))).toEqual(undefined) - }) - - it('returns invalid formula literal', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM('] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellFormula(adr('A1'))).toEqual('=SUM(') - }) - - it('returns invalid matrix formula literal', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE('] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellFormula(adr('A1'))).toEqual('=TRANSPOSE(') - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - engine.getCellFormula({} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#getAllFormulas', () => { - it('should return formulas from all sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['=A()']], - Foo: [[1, '=SUM(A1)']], - }) - - expect(engine.getAllSheetsFormulas()).toEqual({'Foo': [[undefined, '=SUM(A1)']], 'Sheet1': [['=A()']]}) - }) -}) - -describe('#getRangeFormulas', () => { - it('should return formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, A2)', '=TRUE()'], - ['=SUM(', null, 1] - ]) - - const out = engine.getRangeFormulas(AbsoluteCellRange.spanFrom(adr('A1'), 3, 2)) - - expectArrayWithSameContent([['=SUM(1, A2)', '=TRUE()', undefined], ['=SUM(', undefined, undefined]], out) - }) - - it('should throw error if source is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildFromArray([]) - expect(() => { - engine.getRangeFormulas({} as SimpleCellRange) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) -}) - -describe('#getSheetFormulas', () => { - it('should return formulas from sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, A2)', '=TRUE()'], - ['=SUM(', null, 1] - ]) - - const out = engine.getSheetFormulas(0) - - expectArrayWithSameContent([['=SUM(1, A2)', '=TRUE()'], ['=SUM(']], out) - }) -}) - -describe('#getCellValue', () => { - it('should return simple value', () => { - const engine = HyperFormula.buildFromArray([ - ['', 1, '1', 'foo', true, -1.000000000000001] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('D1'))).toEqual('foo') - expect(engine.getCellValue(adr('E1'))).toEqual(true) - expect(engine.getCellValue(adr('F1'))).toEqual(-1) - }) - - it('should return null for empty cells', () => { - const engine = HyperFormula.buildFromArray([ - [null, undefined] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(null) - expect(engine.getCellValue(adr('B1'))).toEqual(null) - expect(engine.getCellValue(adr('C1'))).toEqual(null) - }) - - it('should return value of a formula', () => { - const engine = HyperFormula.buildFromArray([ - ['=1', '=SUM(1, A1)', '=TRUE()', '=1/0'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return parsing error value', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM('] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('should return value of a cell in a formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('should return translated error', () => { - HyperFormula.registerLanguage('plPL', plPL) - const engine = HyperFormula.buildFromArray([ - ['=#ARG!'], - ], {language: 'plPL'}) - - const error = engine.getCellValue(adr('A1')) as DetailedCellError - expect(error).toEqualError(detailedError(ErrorType.VALUE, '', new Config({language: 'plPL'}))) - expect(error.value).toEqual('#ARG!') - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - engine.getCellValue({} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#getSheetDimensions', () => { - it('should work for empty sheet', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.getSheetDimensions(0)).toEqual({height: 0, width: 0}) - }) - - it('should return sheet dimensions', () => { - const engine = HyperFormula.buildFromArray([ - [1, 1], - [1, null, 1], - ]) - - expect(engine.getSheetDimensions(0)).toEqual({height: 2, width: 3}) - }) -}) - -describe('#getAllSheetsDimensions', () => { - it('should return dimension of all sheets', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [], - 'Sheet2': [[1]], - 'Foo': [[null]], - 'Bar': [[null], [null, 'foo']] - }) - - expect(engine.getAllSheetsDimensions()).toEqual({ - 'Sheet1': {width: 0, height: 0}, - 'Sheet2': {width: 1, height: 1}, - 'Foo': {width: 0, height: 0}, - 'Bar': {width: 2, height: 2}, - }) - }) -}) - -describe('#getRangeValues', () => { - it('should return values from range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, B1)', '=TRUE()', null] - ]) - - const out = engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A1'), 3, 1)) - - expectArrayWithSameContent([[1, true, null]], out) - }) - - it('should throw error if source is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildFromArray([]) - expect(() => { - engine.getRangeValues({} as SimpleCellRange) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) -}) - -describe('#getSheetValues', () => { - it('should return values from sheet', () => { - const engine = HyperFormula.buildFromArray([ - [1, 'foo', '=SUM(1, A1)', null, '=TRUE()', null] - ]) - - const out = engine.getSheetValues(0) - - expectArrayWithSameContent([[1, 'foo', 2, null, true]], out) - }) -}) - -describe('#getAllValues', () => { - it('should return values from all sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [], - Foo: [[1]], - }) - - expect(engine.getAllSheetsValues()).toEqual({'Foo': [[1]], 'Sheet1': []}) - }) -}) - -describe('#getCellSerialized', () => { - it('should return formula for formula vertex', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, A2)'] - ]) - - expect(engine.getCellSerialized(adr('A1'))).toEqual('=SUM(1, A2)') - }) - - it('should return formula for parsing error', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM('] - ]) - - expect(engine.getCellSerialized(adr('A1'))).toEqual('=SUM(') - }) - - it('should return simple value', () => { - const engine = HyperFormula.buildFromArray([ - [1, '2', 'foo', true] - ]) - - expect(engine.getCellSerialized(adr('A1'))).toEqual(1) - expect(engine.getCellSerialized(adr('B1'))).toEqual('2') - expect(engine.getCellSerialized(adr('C1'))).toEqual('foo') - expect(engine.getCellSerialized(adr('D1'))).toEqual(true) - }) - - it('should return empty value', () => { - const engine = HyperFormula.buildFromArray([ - [null, undefined] - ]) - - expect(engine.getCellSerialized(adr('A1'))).toEqual(null) - expect(engine.getCellSerialized(adr('B1'))).toEqual(null) - expect(engine.getCellSerialized(adr('C1'))).toEqual(null) - }) - - it('should return formula of a formula matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['{=TRANSPOSE(A1:B1)}'], - ['{=TRANSPOSE(A1:B1)}'], - ]) - - expect(engine.getCellSerialized(adr('A2'))).toEqual('{=TRANSPOSE(A1:B1)}') - expect(engine.getCellSerialized(adr('A3'))).toEqual('{=TRANSPOSE(A1:B1)}') - }) - - it('should return translated error', () => { - HyperFormula.registerLanguage('plPL', plPL) - const engine = HyperFormula.buildFromArray([ - ['=#ARG!'], - ], {language: 'plPL'}) - - expect(engine.getCellSerialized(adr('A1'))).toEqual('=#ARG!') - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - engine.getCellSerialized({} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#getAllSheetsSerialized', () => { - it('should serialize all sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['=A()']], - Foo: [[1]], - Err1: [['=A1']], - Err2: [['234.23141234.2314']], - Err3: [['#DIV/0!']], - }) - - expect(engine.getAllSheetsSerialized()).toEqual({ - 'Foo': [[1]], - 'Sheet1': [['=A()']], - 'Err1': [['=A1']], - 'Err2': [['234.23141234.2314']], - 'Err3': [['#DIV/0!']], - }) - }) -}) - -describe('#getRangeSerialized', () => { - it('should return empty values', () => { - const engine = HyperFormula.buildFromArray([]) - - expectArrayWithSameContent([[null, null]], engine.getRangeSerialized(AbsoluteCellRange.spanFrom(adr('A1'), 2, 1))) - }) - - it('should return serialized cells from range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, B1)', '2', '#VALUE!', null, '=#DIV/0!', '{=TRANSPOSE(A1:B1)}'] - ]) - - const out = engine.getRangeSerialized(AbsoluteCellRange.spanFrom(adr('A1'), 6, 1)) - - expectArrayWithSameContent([['=SUM(1, B1)', '2', '#VALUE!', null, '=#DIV/0!', '{=TRANSPOSE(A1:B1)}']], out) - }) - - it('should throw error if source is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildFromArray([]) - expect(() => { - engine.getRangeSerialized({} as SimpleCellRange) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) -}) - -describe('#sheetName', () => { - it('returns sheet name if sheet exists', () => { - const engine = HyperFormula.buildEmpty() - - engine.addSheet() - - expect(engine.getSheetName(0)).toEqual('Sheet1') - }) - - it('returns undefined if sheet doesnt exists', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.getSheetName(0)).toBeUndefined() - }) -}) - -describe('#sheetId', () => { - it('returns id if sheet exists', () => { - const engine = HyperFormula.buildEmpty() - - engine.addSheet('foobar') - - expect(engine.getSheetId('foobar')).toEqual(0) - }) - - it('returns undefined if sheet doesnt exists', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.getSheetId('doesntexist')).toBeUndefined() - }) -}) - -describe('#doesSheetExist', () => { - it('true if sheet exists', () => { - const engine = HyperFormula.buildEmpty() - - engine.addSheet('foobar') - - expect(engine.doesSheetExist('foobar')).toBe(true) - }) - - it('false if sheet doesnt exist', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.doesSheetExist('foobar')).toBe(false) - }) -}) - -describe('#numberOfSheets', () => { - it('returns 0 if empty', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.countSheets()).toBe(0) - }) - - it('returns number of sheets', () => { - const engine = HyperFormula.buildEmpty() - - engine.addSheet('foo') - - expect(engine.countSheets()).toBe(1) - }) -}) - -describe('#sheetNames', () => { - it('empty engine', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.getSheetNames()).toEqual([]) - }) - - it('returns sheet names', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addSheet('Foo') - - expect(engine.getSheetNames()).toEqual(['Sheet1', 'Foo']) - }) -}) - -describe('#getCellType', () => { - it('empty cell', () => { - const engine = HyperFormula.buildFromArray([[null, undefined]]) - - expect(engine.getCellType(adr('A1'))).toBe(CellType.EMPTY) - expect(engine.getCellType(adr('B1'))).toBe(CellType.EMPTY) - expect(engine.getCellType(adr('C1'))).toBe(CellType.EMPTY) - }) - - it('simple value', () => { - const engine = HyperFormula.buildFromArray([['1', 'foo']]) - - expect(engine.getCellType(adr('A1'))).toBe(CellType.VALUE) - expect(engine.getCellType(adr('B1'))).toBe(CellType.VALUE) - }) - - it('formula', () => { - const engine = HyperFormula.buildFromArray([['=SUM(1, 2)']]) - - expect(engine.getCellType(adr('A1'))).toBe(CellType.FORMULA) - }) - - it('formula matrix', () => { - const engine = HyperFormula.buildFromArray([['=TRANSPOSE(C1:C2)']]) - - expect(engine.getCellType(adr('A1'))).toBe(CellType.ARRAYFORMULA) - expect(engine.getCellType(adr('B1'))).toBe(CellType.ARRAY) - }) - - it('parsing error is a formula cell', () => { - const engine = HyperFormula.buildFromArray([['=SUM(']]) - - expect(engine.getCellType(adr('A1'))).toBe(CellType.FORMULA) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([['=TRANSPOSE(C1:C2)']]) - expect(() => { - engine.getCellType({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#getCellValueDetailedType', () => { - it('string', () => { - const engine = HyperFormula.buildFromArray([['foo']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.STRING) - }) - - it('number data', () => { - const engine = HyperFormula.buildFromArray([['42']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_RAW) - }) - - it('number currency', () => { - const engine = HyperFormula.buildFromArray([['42$']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - }) - - it('number percent', () => { - const engine = HyperFormula.buildFromArray([['42%']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('number date', () => { - const engine = HyperFormula.buildFromArray([['01/01/1967']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_DATE) - }) - - it('number datetime', () => { - const engine = HyperFormula.buildFromArray([['01/01/1967 15:34']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - }) - - it('number time', () => { - const engine = HyperFormula.buildFromArray([['15:34']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_TIME) - }) - - it('boolean', () => { - const engine = HyperFormula.buildFromArray([['=TRUE()']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.BOOLEAN) - }) - - it('empty value', () => { - const engine = HyperFormula.buildFromArray([[null]]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.EMPTY) - expect(engine.getCellValueDetailedType(adr('B1'))).toBe(CellValueDetailedType.EMPTY) - }) - - it('error', () => { - const engine = HyperFormula.buildFromArray([['=1/0', '=SU()', '=A1']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.ERROR) - expect(engine.getCellValueDetailedType(adr('B1'))).toBe(CellValueDetailedType.ERROR) - expect(engine.getCellValueDetailedType(adr('C1'))).toBe(CellValueDetailedType.ERROR) - }) - - it('formula evaluating to range', () => { - const engine = HyperFormula.buildFromArray([['=B1:B2', '=C:D']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.ERROR) - expect(engine.getCellValueDetailedType(adr('B1'))).toBe(CellValueDetailedType.ERROR) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([['=B1:B2', '=C:D']]) - expect(() => { - engine.getCellValueDetailedType({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#getCellValueFormat', () => { - it('non-currency', () => { - const engine = HyperFormula.buildFromArray([['foo']]) - expect(engine.getCellValueFormat(adr('A1'))).toEqual(undefined) - }) - - it('currency', () => { - const engine = HyperFormula.buildFromArray([['1PLN']], {currencySymbol: ['PLN', '$']}) - expect(engine.getCellValueFormat(adr('A1'))).toEqual('PLN') - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_CURRENCY) - }) - - it('unicode currency', () => { - const engine = HyperFormula.buildFromArray([['1₪']], {currencySymbol: ['₪']}) - expect(engine.getCellValueFormat(adr('A1'))).toEqual('₪') - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_CURRENCY) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(() => { - engine.getCellValueFormat({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#getCellValueType', () => { - it('string', () => { - const engine = HyperFormula.buildFromArray([['foo']]) - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('number', () => { - const engine = HyperFormula.buildFromArray([['42', '=SUM(1, A1)']]) - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.NUMBER) - expect(engine.getCellValueType(adr('B1'))).toBe(CellValueType.NUMBER) - }) - - it('boolean', () => { - const engine = HyperFormula.buildFromArray([['=TRUE()']]) - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.BOOLEAN) - }) - - it('empty value', () => { - const engine = HyperFormula.buildFromArray([[null]]) - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.EMPTY) - expect(engine.getCellValueType(adr('B1'))).toBe(CellValueType.EMPTY) - }) - - it('error', () => { - const engine = HyperFormula.buildFromArray([['=1/0', '=SU()', '=A1']]) - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.ERROR) - expect(engine.getCellValueType(adr('B1'))).toBe(CellValueType.ERROR) - expect(engine.getCellValueType(adr('C1'))).toBe(CellValueType.ERROR) - }) - - it('formula evaluating to range', () => { - const engine = HyperFormula.buildFromArray([['=B1:B2', '=C:D']]) - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.ERROR) - expect(engine.getCellValueType(adr('B1'))).toBe(CellValueType.ERROR) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([['=B1:B2', '=C:D']]) - expect(() => { - engine.getCellValueType({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#doesCellHaveSimpleValue', () => { - it('true', () => { - const engine = HyperFormula.buildFromArray([['1', 'foo']]) - expect(engine.doesCellHaveSimpleValue(adr('A1'))).toEqual(true) - expect(engine.doesCellHaveSimpleValue(adr('B1'))).toEqual(true) - }) - - it('false', () => { - const engine = HyperFormula.buildFromArray([['=SUM(1, 2)', null, '=TRANSPOSE(A1:A1)']]) - expect(engine.doesCellHaveSimpleValue(adr('A1'))).toEqual(false) - expect(engine.doesCellHaveSimpleValue(adr('B1'))).toEqual(false) - expect(engine.doesCellHaveSimpleValue(adr('C1'))).toEqual(false) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([['=SUM(1, 2)', null, '=TRANSPOSE(A1:A1)']]) - expect(() => { - engine.doesCellHaveSimpleValue({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#doesCellHaveFormula', () => { - it('true', () => { - const engine = HyperFormula.buildFromArray([['=SUM(1, 2)']]) - expect(engine.doesCellHaveFormula(adr('A1'))).toEqual(true) - }) - - it('false', () => { - const engine = HyperFormula.buildFromArray([['1', '', '{=TRANSPOSE(A1:A1)}', 'foo', null]]) - expect(engine.doesCellHaveFormula(adr('A1'))).toEqual(false) - expect(engine.doesCellHaveFormula(adr('B1'))).toEqual(false) - expect(engine.doesCellHaveFormula(adr('C1'))).toEqual(false) - expect(engine.doesCellHaveFormula(adr('D1'))).toEqual(false) - expect(engine.doesCellHaveFormula(adr('E1'))).toEqual(false) - }) - - it('arrayformula', () => { - const engine = HyperFormula.buildFromArray([['=ARRAYFORMULA(ISEVEN(B1:B2*2))']]) - expect(engine.doesCellHaveFormula(adr('A1'))).toEqual(true) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([['=ARRAYFORMULA(ISEVEN(B1:B2*2))']]) - expect(() => { - engine.doesCellHaveFormula({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#isCellEmpty', () => { - it('true', () => { - const engine = HyperFormula.buildFromArray([[null, undefined]]) - expect(engine.isCellEmpty(adr('A1'))).toEqual(true) - expect(engine.isCellEmpty(adr('B1'))).toEqual(true) - expect(engine.isCellEmpty(adr('C1'))).toEqual(true) - }) - - it('false', () => { - const engine = HyperFormula.buildFromArray([['1', '=SUM(1, 2)', '{=TRANSPOSE(A1:A1)}', 'foo']]) - expect(engine.isCellEmpty(adr('A1'))).toEqual(false) - expect(engine.isCellEmpty(adr('B1'))).toEqual(false) - expect(engine.isCellEmpty(adr('C1'))).toEqual(false) - expect(engine.isCellEmpty(adr('D1'))).toEqual(false) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([['1', '=SUM(1, 2)', '{=TRANSPOSE(A1:A1)}', 'foo']]) - expect(() => { - engine.isCellEmpty({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('#isCellPartOfArray', () => { - it('true', () => { - const engine = HyperFormula.buildFromArray([['=TRANSPOSE(B1:C1)']]) - expect(engine.isCellPartOfArray(adr('A1'))).toEqual(true) - }) - - it('false', () => { - const engine = HyperFormula.buildFromArray([['1', '', '=SUM(1, 2)', 'foo']]) - expect(engine.isCellPartOfArray(adr('A1'))).toEqual(false) - expect(engine.isCellPartOfArray(adr('B1'))).toEqual(false) - expect(engine.isCellPartOfArray(adr('C1'))).toEqual(false) - expect(engine.isCellPartOfArray(adr('D1'))).toEqual(false) - }) - - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([['1', '', '=SUM(1, 2)', 'foo']]) - expect(() => { - engine.isCellPartOfArray({col: 0} as SimpleCellAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')) - }) -}) - -describe('dateTime', () => { - it('dateTime', () => { - const engine = HyperFormula.buildEmpty() - expect(engine.numberToDateTime(43845.1)).toEqual({ - 'day': 15, - 'hours': 2, - 'minutes': 24, - 'month': 1, - 'seconds': 0, - 'year': 2020 - }) - expect(engine.numberToDate(43845)).toEqual({'day': 15, 'month': 1, 'year': 2020}) - expect(engine.numberToTime(1.1)).toEqual({'hours': 26, 'minutes': 24, 'seconds': 0}) - }) -}) - -describe('Graph dependency topological ordering module', () => { - it('should build correctly when rows are dependant on cells that are not yet processed #1', () => { - expect(() => HyperFormula.buildFromArray([ - ['=A3+A2'], - ['=A3'], - ])).not.toThrowError() - }) - - it('should build correctly when rows are dependant on cells that are not yet processed #2', () => { - expect(() => HyperFormula.buildFromArray([ - ['=A4+A3+A2'], - ['=A4+A3'], - ['=A4'], - ])).not.toThrowError() - }) - - it('should build correctly when rows are dependant on cells that are not yet processed #3', () => { - expect(() => HyperFormula.buildFromArray([ - ['=A5+A4+A3+A2'], - ['=A5+A4+A3'], - ['=A5+A4'], - ['=A5'], - ])).not.toThrowError() - }) -}) - -describe('#getFillRangeData from corner source', () => { - it('should properly apply wrap-around #1', () => { - const engine = HyperFormula.buildFromArray([[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']]) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2), AbsoluteCellRange.spanFrom(adr('C3'), 3, 3)) - ).toEqual([['2', '=$A$1', '2'], ['=A3', 1, '=C3'], ['2', '=$A$1', '2']]) - }) - - it('should properly apply wrap-around #2', () => { - const engine = HyperFormula.buildFromArray([[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']]) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2), AbsoluteCellRange.spanFrom(adr('B2'), 3, 3)) - ).toEqual([[1, '=A1', 1], ['=$A$1', '2', '=$A$1'], [1, '=A3', 1]]) - }) - - it('should properly apply wrap-around #3', () => { - const engine = HyperFormula.buildFromArray([[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']]) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2), AbsoluteCellRange.spanFrom(adr('A1'), 3, 3)) - ).toEqual([['2', '=$A$1', '2'], ['=#REF!', 1, '=A1'], ['2', '=$A$1', '2']]) - }) -}) - -describe('#getFillRangeData from target source', () => { - it('should properly apply wrap-around #1', () => { - const engine = HyperFormula.buildFromArray([[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']]) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2), AbsoluteCellRange.spanFrom(adr('C3'), 3, 3), true) - ).toEqual([[1, '=B2', 1], ['=$A$1', '2', '=$A$1'], [1, '=B4', 1]]) - }) - - it('should properly apply wrap-around #2', () => { - const engine = HyperFormula.buildFromArray([[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']]) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2), AbsoluteCellRange.spanFrom(adr('B2'), 3, 3), true) - ).toEqual([[1, '=A1', 1], ['=$A$1', '2', '=$A$1'], [1, '=A3', 1]]) - }) - - it('should properly apply wrap-around #3', () => { - const engine = HyperFormula.buildFromArray([[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']]) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2'), 2, 2), AbsoluteCellRange.spanFrom(adr('A1'), 3, 3), true) - ).toEqual([[1, '=#REF!', 1], ['=$A$1', '2', '=$A$1'], [1, '=#REF!', 1]]) - }) -}) - -describe('#getFillRangeData', () => { - it('should move between sheets - sheet relative addresses', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']], - 'Sheet2': [], - } - ) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2', 0), 2, 2), AbsoluteCellRange.spanFrom(adr('C3', 1), 3, 3)) - ).toEqual([['2', '=$A$1', '2'], ['=A3', 1, '=C3'], ['2', '=$A$1', '2']]) - }) - - it('should move between sheets - sheet absolute addresses', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [[], [undefined, 1, '=Sheet1!A1'], [undefined, '=Sheet2!$A$1', '2']], - 'Sheet2': [], - } - ) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2', 0), 2, 2), AbsoluteCellRange.spanFrom(adr('C3', 1), 3, 3)) - ).toEqual([['2', '=Sheet2!$A$1', '2'], ['=Sheet1!A3', 1, '=Sheet1!C3'], ['2', '=Sheet2!$A$1', '2']]) - }) - - it('should move between sheets - no sheet of a given name', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [], - } - ) - - expect(engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('B2', 0), 1, 1), AbsoluteCellRange.spanFrom(adr('C3', 1), 1, 1)) - ).toEqual([[null]]) - }) - - it('should throw error if source is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']], - 'Sheet2': [], - }) - expect(() => { - engine.getFillRangeData({} as SimpleCellRange, AbsoluteCellRange.spanFrom(adr('C3', 1), 3, 3)) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'source')) - }) - - it('should throw error if target is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [[], [undefined, 1, '=A1'], [undefined, '=$A$1', '2']], - 'Sheet2': [], - }) - expect(() => { - engine.getFillRangeData(AbsoluteCellRange.spanFrom(adr('C3', 1), 3, 3), {} as SimpleCellRange) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'target')) - }) -}) - -describe('#simpleCellRangeToString', () => { - it('return a string for a cell range', () => { - const engine = HyperFormula.buildFromArray([[]]) - expect(engine.simpleCellRangeToString(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2), 0)).toBe('A1:B2') - }) - - it('should throw error if cellRange is a malformed SimpleCellRange', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - 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', () => { - it('should throw error if cellAddress is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildEmpty() - expect(() => { - 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', () => { - it('should convert a string to a simpleCellAddress', () => { - const engine = HyperFormula.buildEmpty() - expect(engine.simpleCellAddressFromString('C5', 2)).toEqual(simpleCellAddress(2, 2, 4)) - }) - - it('should work for address with sheet name', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [], - }) - expect(engine.simpleCellAddressFromString('Sheet1!C5', 2)).toEqual(simpleCellAddress(0, 2, 4)) - }) - - it('should work when sheet name contains unicode characters (sheet name in single quotes)', () => { - // noinspection NonAsciiCharacters - const engine = HyperFormula.buildFromSheets({ - あは: [], - }) - expect(engine.simpleCellAddressFromString("'あは'!C5", 2)).toEqual(simpleCellAddress(0, 2, 4)) - }) - - it('should return undefined when sheet name contains unicode characters (unquoted sheet name)', () => { - // noinspection NonAsciiCharacters - const engine = HyperFormula.buildFromSheets({ - あは: [], - }) - expect(engine.simpleCellAddressFromString('あは!C5', 2)).toBe(undefined) - }) -}) - -describe('#simpleCellRangeFromString', () => { - it('should convert a string to a simpleCellRange', () => { - 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) - }) -}) diff --git a/test/unit/error-address-preservation.spec.ts b/test/unit/error-address-preservation.spec.ts deleted file mode 100644 index 1b04fc92c7..0000000000 --- a/test/unit/error-address-preservation.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {simpleCellRange} from '../../src/AbsoluteCellRange' -import {adr, detailedErrorWithOrigin} from './testUtils' - -describe('Address preservation.', () => { - it('Should work in the basic case.', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=A1'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!A1')) - expect(engine.getCellValue(adr('B1'))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!A1')) - }) - - it('Should work with named expressions.', () => { - const engine = HyperFormula.buildFromArray([ - ['=NAMEDEXPRESSION', '=A1'] - ]) - engine.addNamedExpression('NAMEDEXPRESSION', '=NA()') - expect(engine.getCellValue(adr('A1'))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'NAMEDEXPRESSION')) - expect(engine.getCellValue(adr('B1'))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'NAMEDEXPRESSION')) - }) - - it('Should work with operators.', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=NA()', '=A1+B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!A1')) - }) - - it('Should work between sheets.', () => { - const engine = HyperFormula.buildFromSheets({ - sheet1: [['=NA()']], - sheet2: [['=sheet1!A1']] - }) - expect(engine.getCellValue(adr('A1', 0))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'sheet1!A1')) - expect(engine.getCellValue(adr('A1', 1))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'sheet1!A1')) - }) - - it('Should work with function calls.', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=DATE(1,1,A1)'] - ]) - expect(engine.getCellValue(adr('B1'))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!A1')) - }) - - it('Should work with CYCLE.', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '=A1'], - ['=A1', '=B1'], - ['=A1', '=B1'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1')) - expect(engine.getCellValue(adr('B1'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B1')) - expect(engine.getCellValue(adr('A2'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1')) - expect(engine.getCellValue(adr('B2'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B1')) - expect(engine.getCellValue(adr('A3'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1')) - expect(engine.getCellValue(adr('B3'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B1')) - }) - - it('Should work with CYCLE #2.', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '=A1'], - ['=A1'], - ['=A1'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1')) - expect(engine.getCellValue(adr('B1'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B1')) - expect(engine.getCellValue(adr('A2'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1')) - expect(engine.getCellValue(adr('A3'))).toEqual(detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1')) - }) - - it('Should work after simple cruds', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=A1'] - ]) - - engine.addColumns(0, [0, 1]) - expect(engine.getCellValue(adr('C1'))).toEqual(detailedErrorWithOrigin(ErrorType.NA, 'Sheet1!B1')) - - engine.setCellContents(adr('B1'), '=1/0') - expect(engine.getCellValue(adr('C1'))).toEqual(detailedErrorWithOrigin(ErrorType.DIV_BY_ZERO, 'Sheet1!B1')) - - engine.moveCells(simpleCellRange(adr('B1'), adr('B1')), adr('C5')) - expect(engine.getCellValue(adr('C1'))).toEqual(detailedErrorWithOrigin(ErrorType.DIV_BY_ZERO, 'Sheet1!C5')) - }) -}) diff --git a/test/unit/escaping-support.spec.ts b/test/unit/escaping-support.spec.ts deleted file mode 100644 index 11e326c6f7..0000000000 --- a/test/unit/escaping-support.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {HyperFormula} from '../../src' -import {adr} from './testUtils' - -describe('escaped formulas', () => { - it('should serialize properly', () => { - const engine = HyperFormula.buildFromArray([['\'=SUM(2,2)']]) - expect(engine.getCellSerialized(adr('A1'))).toEqual('\'=SUM(2,2)') - expect(engine.getCellValue(adr('A1'))).toEqual('=SUM(2,2)') - }) -}) diff --git a/test/unit/extending-plugins.spec.ts b/test/unit/extending-plugins.spec.ts deleted file mode 100644 index e222c08aa2..0000000000 --- a/test/unit/extending-plugins.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {ErrorMessage} from '../../src/error-message' -import {InterpreterState} from '../../src/interpreter/InterpreterState' -import {FunctionPlugin, FunctionPluginTypecheck} from '../../src/interpreter/plugin/FunctionPlugin' -import {ProcedureAst} from '../../src/parser' -import {adr, detailedError} from './testUtils' - -class FooPlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'FOO': { - method: 'foo', - }, - } - - public foo(_ast: ProcedureAst, _state: InterpreterState) { - return 42 - } -} - -describe('Plugins', () => { - it('Extending with a plugin', () => { - HyperFormula.getLanguage('enGB').extendFunctions({'FOO': 'FOO'}) - const engine = HyperFormula.buildFromArray([ - ['=foo()'], - ], {functionPlugins: [FooPlugin]}) - - expect(engine.getCellValue(adr('A1'))).toBe(42) - }) - - it('cleanup', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo()'], - ], {functionPlugins: [FooPlugin]}) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOO'))) - }) -}) diff --git a/test/unit/find-boundaries.spec.ts b/test/unit/find-boundaries.spec.ts deleted file mode 100644 index 8d6e6253a5..0000000000 --- a/test/unit/find-boundaries.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import {findBoundaries} from '../../src/Sheet' - -describe('findBoundaries', () => { - it('find correct dimensions', () => { - expect(findBoundaries([ - ['1', '2'], - ['1', '2', '3'], - ])).toMatchObject({height: 2, width: 3}) - }) - - it('find correct dimensions when empty cell at the end of row', () => { - expect(findBoundaries([ - ['1', '2'], - ['1', '2', null], - ])).toMatchObject({height: 2, width: 2}) - }) - - it('find correct dimensions when empty cell in the middle of the row', () => { - expect(findBoundaries([ - ['1', '2'], - ['1', '2', null, '4'], - ])).toMatchObject({height: 2, width: 4}) - }) - - it('find correct dimensions when empty row', () => { - expect(findBoundaries([ - ['1', '2'], - ['1', '2'], - [null], - [], - ])).toMatchObject({height: 2, width: 2}) - }) - - it('returns sane dimensions for empty cases', () => { - expect(findBoundaries([])).toMatchObject({height: 0, width: 0}) - expect(findBoundaries([[]])).toMatchObject({height: 0, width: 0}) - }) - - it('calculate correct fill for array with different size', () => { - expect(findBoundaries([ - ['1', '2'], - ['1', '2', '3'], - ])).toMatchObject({fill: 5 / 6}) - }) - - it('calculate correct fill for empty arrays', () => { - expect(findBoundaries([]).fill).toBe(0) - expect(findBoundaries([[]]).fill).toBe(0) - }) - - it('calculate correct fill for array with one element', () => { - expect(findBoundaries([[null]]).fill).toBe(0) - expect(findBoundaries([['x']]).fill).toBe(1) - }) - - it('does count empty string', () => { - expect(findBoundaries([ - ['1', ''], - ['1', '2'], - ])).toMatchObject({fill: 1}) - }) - - it('does not count empty value', () => { - expect(findBoundaries([ - ['1', null], - ['1', '2'], - ])).toMatchObject({fill: 3 / 4}) - }) - - it('does not count null', () => { - expect(findBoundaries([ - ['1', null], - ['1', '2'], - ])).toMatchObject({fill: 3 / 4}) - }) - - it('does not count undefined', () => { - expect(findBoundaries([ - ['1', undefined], - ['1', '2'], - ])).toMatchObject({fill: 3 / 4}) - }) -}) diff --git a/test/unit/format/format-interpreter.spec.ts b/test/unit/format/format-interpreter.spec.ts deleted file mode 100644 index aac301295f..0000000000 --- a/test/unit/format/format-interpreter.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {Config} from '../../../src/Config' -import {DateTimeHelper} from '../../../src/DateTimeHelper' -import {format} from '../../../src/format/format' - -describe('FormatInterpreter', () => { - const config = new Config() - const dateHelper = new DateTimeHelper(config) - it('works for expression without significant tokens', () => { - expect(format(2, 'Foo', config, dateHelper)).toEqual('Foo') - }) - - it('works for simple date expression', () => { - expect(format(2, 'dd-mm-yyyy', config, dateHelper)).toEqual('01-01-1900') - }) - - it('works with # without decimal separator', () => { - expect(format(1, '###', config, dateHelper)).toEqual('1') - expect(format(12, '###', config, dateHelper)).toEqual('12') - expect(format(123, '###', config, dateHelper)).toEqual('123') - expect(format(123.4, '###', config, dateHelper)).toEqual('123') - expect(format(1234, '###', config, dateHelper)).toEqual('1234') - }) - - it('works with # number format with decimal separator', () => { - expect(format(1, '#.##', config, dateHelper)).toEqual('1.') - expect(format(12, '#.##', config, dateHelper)).toEqual('12.') - expect(format(12.34, '#.##', config, dateHelper)).toEqual('12.34') - expect(format(12.345, '#.##', config, dateHelper)).toEqual('12.35') - }) - - it('works with 0 without decimal separator', () => { - expect(format(1, '000', config, dateHelper)).toEqual('001') - expect(format(12, '000', config, dateHelper)).toEqual('012') - expect(format(123, '000', config, dateHelper)).toEqual('123') - expect(format(123.4, '000', config, dateHelper)).toEqual('123') - expect(format(1234, '000', config, dateHelper)).toEqual('1234') - }) - - it('works with 0 number format', () => { - expect(format(1, '00.00', config, dateHelper)).toEqual('01.00') - expect(format(12, '00.00', config, dateHelper)).toEqual('12.00') - expect(format(12.3, '00.00', config, dateHelper)).toEqual('12.30') - expect(format(12.34, '00.00', config, dateHelper)).toEqual('12.34') - expect(format(12.345, '00.00', config, dateHelper)).toEqual('12.35') - }) - - it('number formatting with additional chars', () => { - expect(format(1, '$0.00', config, dateHelper)).toEqual('$1.00') - }) -}) diff --git a/test/unit/format/format-parser.spec.ts b/test/unit/format/format-parser.spec.ts deleted file mode 100644 index 1e2aadb792..0000000000 --- a/test/unit/format/format-parser.spec.ts +++ /dev/null @@ -1,84 +0,0 @@ -import {FormatExpressionType, parse, TokenType} from '../../../src/format/parser' - -describe('FormatParser', () => { - it('works for escaped characters', () => { - const parseResult = parse('\\ddd') - - expect(parseResult.type).toBe(FormatExpressionType.DATE) - expect(parseResult.tokens.length).toBe(2) - expect(parseResult.tokens[0]).toEqual({ - type: TokenType.FREE_TEXT, - value: '\\d', - }) - expect(parseResult.tokens[1]).toEqual({ - type: TokenType.FORMAT, - value: 'dd', - }) - }) - - it('works only for escaped characters', () => { - const parseResult = parse('\\d\\d') - - expect(parseResult.type).toBe(FormatExpressionType.STRING) - expect(parseResult.tokens.length).toBe(1) - expect(parseResult.tokens[0]).toEqual({ - type: TokenType.FREE_TEXT, - value: '\\d\\d', - }) - }) - - it('works for date format', () => { - const parseResult = parse('dd-mm-yyyy') - - expect(parseResult.type).toBe(FormatExpressionType.DATE) - }) - - it('works for number format', () => { - const parseResult = parse('#.###') - - expect(parseResult.type).toBe(FormatExpressionType.NUMBER) - }) - - it('works for date format and free text', () => { - const parseResult = parse('dd foo') - - expect(parseResult.type).toBe(FormatExpressionType.DATE) - expect(parseResult.tokens.length).toBe(2) - - expect(parseResult.tokens[0]).toEqual({ - type: TokenType.FORMAT, - value: 'dd', - }) - - expect(parseResult.tokens[1]).toEqual({ - type: TokenType.FREE_TEXT, - value: ' foo', - }) - }) - - it('works without any formatting tokens', () => { - const parseResult = parse('foo') - - expect(parseResult.type).toBe(FormatExpressionType.STRING) - expect(parseResult.tokens[0]).toEqual({ - type: TokenType.FREE_TEXT, - value: 'foo', - }) - }) - - it('matches only one number tokens group', () => { - const parseResult = parse('#.### #.###') - - expect(parseResult.type).toBe(FormatExpressionType.NUMBER) - - expect(parseResult.tokens[0]).toEqual({ - type: TokenType.FORMAT, - value: '#.###', - }) - - expect(parseResult.tokens[1]).toEqual({ - type: TokenType.FREE_TEXT, - value: ' #.###', - }) - }) -}) diff --git a/test/unit/functions-metadata.spec.ts b/test/unit/functions-metadata.spec.ts deleted file mode 100644 index ee4337f86f..0000000000 --- a/test/unit/functions-metadata.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {HyperFormula} from '../../src' - -describe('All functions', () => { - it('should all contain metadata', () => { - const engine = HyperFormula.buildEmpty() - for (const functionId of engine.getRegisteredFunctionNames()) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const metadata = engine._functionRegistry.getMetadata(functionId) - expect(metadata).not.toBe(undefined) - } - }) - - it('should all contain param definition in metadata', () => { - const engine = HyperFormula.buildEmpty() - for (const functionId of engine.getRegisteredFunctionNames()) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const params = engine._functionRegistry.getMetadata(functionId)?.parameters - expect(params).not.toBe(undefined) - } - }) -}) diff --git a/test/unit/generate-cells-range.spec.ts b/test/unit/generate-cells-range.spec.ts deleted file mode 100644 index eb82a14341..0000000000 --- a/test/unit/generate-cells-range.spec.ts +++ /dev/null @@ -1,173 +0,0 @@ -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {SimpleCellAddress} from '../../src/Cell' -import {Config} from '../../src/Config' -import {DependencyGraph} from '../../src/DependencyGraph' -import {FunctionRegistry} from '../../src/interpreter/FunctionRegistry' -import {LazilyTransformingAstService} from '../../src/LazilyTransformingAstService' -import {NamedExpressions} from '../../src/NamedExpressions' -import {RowsSpan} from '../../src/Span' -import {Statistics} from '../../src/statistics/Statistics' -import {adr} from './testUtils' - -describe('generateCellsFromRange', () => { - const config = new Config() - const functionRegistry = new FunctionRegistry(config) - const stats = new Statistics() - const lazilyTransformingAstService = new LazilyTransformingAstService(stats) - const dependencyGraph = DependencyGraph.buildEmpty(lazilyTransformingAstService, config, functionRegistry, new NamedExpressions(), stats) - const generateCellsFromRange = (range: AbsoluteCellRange): SimpleCellAddress[] => { - return Array.from(range.addresses(dependencyGraph)) - } - - it('one element', () => { - expect(generateCellsFromRange(new AbsoluteCellRange(adr('A1'), adr('A1')))).toEqual([ - adr('A1'), - ]) - }) - - it('simple row', () => { - expect(generateCellsFromRange(new AbsoluteCellRange(adr('A1'), adr('B1')))).toEqual([ - adr('A1'), - adr('B1'), - ]) - }) - - it('simple column', () => { - expect(generateCellsFromRange(new AbsoluteCellRange(adr('A1'), adr('A2')))).toEqual([ - adr('A1'), - adr('A2'), - ]) - }) - - it('simple square', () => { - expect(generateCellsFromRange(new AbsoluteCellRange(adr('A1'), adr('B2')))).toEqual([ - adr('A1'), - adr('B1'), - adr('A2'), - adr('B2'), - ]) - }) -}) - -describe('AbsoluteCellRange#sameDimensions', () => { - it('same width and height', () => { - const range1 = new AbsoluteCellRange(adr('B1'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('L11'), adr('M14')) - expect(range1.sameDimensionsAs(range2)).toBe(true) - }) - - it('different width', () => { - const range1 = new AbsoluteCellRange(adr('B1'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('L11'), adr('N14')) - expect(range1.sameDimensionsAs(range2)).toBe(false) - }) - - it('different height', () => { - const range1 = new AbsoluteCellRange(adr('B1'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('L11'), adr('M15')) - expect(range1.sameDimensionsAs(range2)).toBe(false) - }) -}) - -describe('AbsoluteCellRange#doesOverlap', () => { - it('exactly the same', () => { - const range1 = new AbsoluteCellRange(adr('B1'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('B1'), adr('C4')) - expect(range1.doesOverlap(range2)).toBe(true) - }) - - it('different sheets', () => { - const range1 = new AbsoluteCellRange(adr('B1'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('B1', 1), adr('C4', 1)) - expect(range1.doesOverlap(range2)).toBe(false) - }) - - it('second on the right side of the first', () => { - const range1 = new AbsoluteCellRange(adr('B1'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('D1'), adr('E4')) - expect(range1.doesOverlap(range2)).toBe(false) - }) - - it('second on the left side of the first', () => { - const range1 = new AbsoluteCellRange(adr('B1'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('A1'), adr('A4')) - expect(range1.doesOverlap(range2)).toBe(false) - }) - - it('second on the top of the first', () => { - const range1 = new AbsoluteCellRange(adr('B3'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('B1'), adr('C2')) - expect(range1.doesOverlap(range2)).toBe(false) - }) - - it('second on the bottom of the first', () => { - const range1 = new AbsoluteCellRange(adr('B3'), adr('C4')) - const range2 = new AbsoluteCellRange(adr('B5'), adr('C6')) - expect(range1.doesOverlap(range2)).toBe(false) - }) -}) - -describe('AbsoluteCellRange#width', () => { - it('a column', () => { - expect(new AbsoluteCellRange(adr('B1'), adr('B11')).width()).toBe(1) - }) - - it('more columns', () => { - expect(new AbsoluteCellRange(adr('B1'), adr('D11')).width()).toBe(3) - }) -}) - -describe('AbsoluteCellRange#height', () => { - it('a row', () => { - expect(new AbsoluteCellRange(adr('B2'), adr('K2')).height()).toBe(1) - }) - - it('more rows', () => { - expect(new AbsoluteCellRange(adr('B2'), adr('K4')).height()).toBe(3) - }) -}) - -describe('AbsoluteCellRange#removeSpan', () => { - it('rows below', () => { - const range = new AbsoluteCellRange(adr('A1'), adr('A4')) - range.removeSpan(new RowsSpan(0, 4, 5)) - expect(range.start.row).toBe(0) - expect(range.end.row).toBe(3) - }) - - it('rows above', () => { - const range = new AbsoluteCellRange(adr('A3'), adr('A5')) - range.removeSpan(new RowsSpan(0, 0, 1)) - expect(range.start.row).toBe(0) - expect(range.end.row).toBe(2) - }) - - it('middle of the range', () => { - const range = new AbsoluteCellRange(adr('A1'), adr('A5')) - range.removeSpan(new RowsSpan(0, 1, 2)) - expect(range.start.row).toBe(0) - expect(range.end.row).toBe(2) - }) - - it('start above range', () => { - const range = new AbsoluteCellRange(adr('A3'), adr('A5')) - range.removeSpan(new RowsSpan(0, 0, 3)) - expect(range.start.row).toBe(0) - expect(range.end.row).toBe(0) - }) - - it('end below range', () => { - const range = new AbsoluteCellRange(adr('A1'), adr('A5')) - range.removeSpan(new RowsSpan(0, 2, 5)) - expect(range.start.row).toBe(0) - expect(range.end.row).toBe(1) - }) - - it('whole range', () => { - const range = new AbsoluteCellRange(adr('A3'), adr('A5')) - range.removeSpan(new RowsSpan(0, 0, 5)) - expect(range.start.row).toBe(0) - expect(range.end.row).toBe(-1) - expect(range.height()).toBe(0) - }) -}) diff --git a/test/unit/generatorUtils.spec.ts b/test/unit/generatorUtils.spec.ts deleted file mode 100644 index efa90368c1..0000000000 --- a/test/unit/generatorUtils.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {empty, first, split} from '../../src/generatorUtils' - -describe('empty', () => { - it('works', () => { - expect(Array.from(empty())).toEqual([]) - }) -}) - -describe('split', () => { - it('works for empty case', () => { - const result = split(empty()) - - expect(result.value).toBe(undefined) - expect(Array.from(result.rest)).toEqual([]) - }) - - it('works for one element case', () => { - const arr = [42] - - const result = split(arr[Symbol.iterator]()) - - expect(result.value).toBe(42) - expect(Array.from(result.rest)).toEqual([]) - }) - - it('works for more elements case', () => { - const arr = [42, 43] - - const result = split(arr[Symbol.iterator]()) - - expect(result.value).toBe(42) - expect(Array.from(result.rest)).toEqual([43]) - }) -}) - -describe('first', () => { - it('works for empty case', () => { - expect(first(empty())).toBe(undefined) - }) - - it('works for one element case', () => { - const arr = [42] - - expect(first(arr[Symbol.iterator]())).toEqual(42) - }) - - it('works for more elements case', () => { - const arr = [42, 43] - - expect(first(arr[Symbol.iterator]())).toEqual(42) - }) -}) diff --git a/test/unit/graph-builder.spec.ts b/test/unit/graph-builder.spec.ts deleted file mode 100644 index 0041398fa3..0000000000 --- a/test/unit/graph-builder.spec.ts +++ /dev/null @@ -1,165 +0,0 @@ -import {HyperFormula} from '../../src' -import {Config} from '../../src/Config' -import {EmptyCellVertex, ValueCellVertex} from '../../src/DependencyGraph' -import {SheetSizeLimitExceededError} from '../../src/errors' -import {adr, colEnd, colStart, graphEdgesCount} from './testUtils' - -describe('GraphBuilder', () => { - it('build sheet with simple number cell', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - - const vertex = engine.addressMapping.getCell(adr('A1')) - expect(vertex).toBeInstanceOf(ValueCellVertex) - expect(vertex!.getCellValue()).toBe(42) - }) - - it('build sheet with simple string cell', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - ]) - - const vertex = engine.addressMapping.getCell(adr('A1')) - expect(vertex).toBeInstanceOf(ValueCellVertex) - expect(vertex!.getCellValue()).toBe('foo') - }) - - it('building for cell with null should give empty vertex', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=A1'], - ]) - - const vertex = engine.addressMapping.getCell(adr('A1')) - expect(vertex).toBeInstanceOf(EmptyCellVertex) - }) - - it('#buildGraph works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=A1:B1'], - ]) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const a1b2 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('B1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(engine.graph.adjacentNodes(a1!)).toContain(a1b2) - expect(engine.graph.adjacentNodes(b1!)).toContain(a1b2) - expect(engine.graph.adjacentNodes(a1b2)).toContain(a2) - }) - - it('#buildGraph works with column ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=A:B'], - ]) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const ab = engine.rangeMapping.getVertexOrThrow(colStart('A'), colEnd('B')) - const c1 = engine.addressMapping.getCell(adr('C1')) - expect(engine.graph.adjacentNodes(a1!)).toContain(ab) - expect(engine.graph.adjacentNodes(b1!)).toContain(ab) - expect(engine.graph.adjacentNodes(ab)).toContain(c1) - }) - - it('#loadSheet - it should build graph with only one RangeVertex', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=A1:B1'], - ['=A1:B1'], - ]) - - const a1 = engine.addressMapping.getCell(adr('A1')) - const b1 = engine.addressMapping.getCell(adr('B1')) - const a1b2 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('B1')) - const a2 = engine.addressMapping.getCell(adr('A2')) - const a3 = engine.addressMapping.getCell(adr('A3')) - - expect(engine.graph.existsEdge(a1!, a1b2)).toBe(true) - expect(engine.graph.existsEdge(b1!, a1b2)).toBe(true) - expect(engine.graph.existsEdge(a1b2, a2!)).toBe(true) - expect(engine.graph.existsEdge(a1b2, a3!)).toBe(true) - expect(engine.graph.getNodes().length).toBe( - 4 + // for cells above - 1, // for both ranges (reuse same ranges) - ) - }) - - it('build with range one row smaller', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '0'], - ['3', '=A1:A2'], - ['5', '=A1:A3'], - ]) - - const a3 = engine.addressMapping.getCell(adr('A3')) - const a1a2 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) - const a1a3 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) - - expect(engine.graph.existsEdge(a3!, a1a3)).toBe(true) - expect(engine.graph.existsEdge(a1a2, a1a3)).toBe(true) - expect(graphEdgesCount(engine.graph)).toBe( - 2 + // from cells to range(A1:A2) - 2 + // from A3 and range(A1:A2) to range(A1:A3) - 2, // from range vertexes to formulas - ) - }) - - it('#buildGraph should work even if range dependencies are empty', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '0', '=SUM(A1:B2)'], - ]) - - expect(engine.graph.getNodes().length).toBe( - 3 + // for cells above - 1 + // for range vertex - 2, // for 2 EmptyCellVertex instances - ) - expect(graphEdgesCount(engine.graph)).toBe( - 2 + // from cells to range vertex - 2 + // from EmptyCellVertex instances to range vertices - 1, // from range to cell with SUM - ) - }) - - it("optimization doesn't work if smaller range is after bigger", () => { - const engine = HyperFormula.buildFromArray([ - ['1', '0'], - ['3', '=A1:A3'], - ['5', '=A1:A2'], - ]) - - const a1a2 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A2')) - const a1a3 = engine.rangeMapping.getVertexOrThrow(adr('A1'), adr('A3')) - const a2 = engine.addressMapping.getCell(adr('A2')) - expect(engine.graph.existsEdge(a2!, a1a3)).toBe(true) - expect(engine.graph.existsEdge(a2!, a1a2)).toBe(true) - expect(engine.graph.existsEdge(a1a2, a1a3)).toBe(false) - expect(graphEdgesCount(engine.graph)).toBe( - 3 + // from 3 cells to range(A1:A2) - 2 + // from 2 cells to range(A1:A2) - 2, // from range vertexes to formulas - ) - }) -}) - -describe('Sheet size limits', () => { - it('should throw error when trying to build engine with too many columns', () => { - const maxColumns = Config.defaultConfig.maxColumns - const sheet = [new Array(maxColumns + 1).fill('')] - - expect(() => { - HyperFormula.buildFromArray(sheet) - }).toThrow(new SheetSizeLimitExceededError()) - }) - - it('should throw error when trying to build engine with too many rows', () => { - const maxRows = Config.defaultConfig.maxRows - const sheet = new Array(maxRows + 1).fill(['']) - - expect(() => { - HyperFormula.buildFromArray(sheet) - }).toThrow(new SheetSizeLimitExceededError()) - }) -}) diff --git a/test/unit/graph-dependencies-queries.spec.ts b/test/unit/graph-dependencies-queries.spec.ts deleted file mode 100644 index ea35ed7057..0000000000 --- a/test/unit/graph-dependencies-queries.spec.ts +++ /dev/null @@ -1,169 +0,0 @@ -import {HyperFormula, SimpleCellAddress} from '../../src' -import {simpleCellRange} from '../../src/AbsoluteCellRange' -import {adr} from './testUtils' -import {ExpectedValueOfTypeError} from '../../src/errors' - -describe('address queries', () => { - describe('getCellDependents', () => { - it('should return reversed dependencies', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=SUM(A1:B1)', '=SUMSQ(A1:B1)'], - ['=A2+B2'], - ]) - expect(engine.getCellDependents(adr('A1'))).toEqual([simpleCellRange(adr('A1'), adr('B1'))]) - expect(engine.getCellDependents(adr('D1'))).toEqual([]) - expect(engine.getCellDependents(adr('A2'))).toEqual([adr('A3')]) - expect(engine.getCellDependents(adr('B2'))).toEqual([adr('A3')]) - expect(engine.getCellDependents(adr('A3'))).toEqual([]) - - expect(engine.getCellDependents(simpleCellRange(adr('A1'), adr('B1')))).toEqual([adr('A2'), adr('B2')]) - expect(engine.getCellDependents(simpleCellRange(adr('A3'), adr('B3')))).toEqual([]) - }) - - it('should return reversed dependencies across sheets', () => { - const engine = HyperFormula.buildFromSheets( - { - 'DataSheet': [[1, 2, 3, '=A1']], - 'DependentSheet': [['=DataSheet!A1', '=DataSheet!A1', '=DataSheet!A1+DataSheet!B1', '=A1']], - } - ) - - const dataSheetId = engine.getSheetId('DataSheet') - const dependentSheetId = engine.getSheetId('DependentSheet') - - expect(engine.getCellDependents(adr('A1', dataSheetId))).toEqual([ - adr('D1', dataSheetId), - adr('A1', dependentSheetId), - adr('B1', dependentSheetId), - adr('C1', dependentSheetId) - ]) - expect(engine.getCellDependents(adr('B1', dataSheetId))).toEqual([adr('C1', dependentSheetId)]) - expect(engine.getCellDependents(adr('C1', dataSheetId))).toEqual([]) - expect(engine.getCellDependents(adr('D1', dataSheetId))).toEqual([]) - }) - - it('should return only immediate reversed dependencies', () => { - const hfInstance = HyperFormula.buildFromArray([[ '1', '=A1', '=A1+B1', '=B1+C1' ]]) - - const dependents = hfInstance.getCellDependents({ sheet: 0, col: 0, row: 0 }) - - expect(dependents).toEqual([ - { sheet: 0, col: 1, row: 0 }, - { sheet: 0, col: 2, row: 0 }, - ]) - }) - - it('should return named expressions dependents as cell references in sheet -1', () => { - const hfInstance = HyperFormula.buildFromArray([[ '1' ]]) - hfInstance.addNamedExpression('foo', '=Sheet1!$A$1') - - const dependents = hfInstance.getCellDependents({ sheet: 0, col: 0, row: 0 }) - - expect(dependents).toEqual([ - { sheet: -1, col: 0, row: 0 }, - ]) - }) - - it('should throw error if address is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=SUM(A1:B1)', '=SUMSQ(A1:B1)'], - ['=A2+B2'], - ]) - - const malformedAddress = {col: 0} as SimpleCellAddress - - expect(() => { - engine.getCellDependents(malformedAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress | SimpleCellRange', malformedAddress.toString())) - }) - - it('should return empty array when sheet does not exist', () => { - const engine = HyperFormula.buildFromArray([[1]]) - - const nonExistentSheetId = 999 - - expect(engine.getCellDependents({ sheet: nonExistentSheetId, col: 0, row: 0 })).toEqual([]) - }) - }) - - describe('getCellPrecedents', () => { - it('should return dependencies', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=SUM(A1:B1)', '=SUMSQ(A1:B1)'], - ['=A2+B2'], - ]) - expect(engine.getCellPrecedents(adr('A1'))).toEqual([]) - expect(engine.getCellPrecedents(adr('D1'))).toEqual([]) - expect(engine.getCellPrecedents(adr('A2'))).toEqual([simpleCellRange(adr('A1'), adr('B1'))]) - expect(engine.getCellPrecedents(adr('B2'))).toEqual([simpleCellRange(adr('A1'), adr('B1'))]) - expect(engine.getCellPrecedents(adr('A3'))).toEqual([adr('A2'), adr('B2')]) - - expect(engine.getCellPrecedents(simpleCellRange(adr('A1'), adr('B1')))).toEqual([adr('A1'), adr('B1')]) - expect(engine.getCellPrecedents(simpleCellRange(adr('A3'), adr('B3')))).toEqual([]) - }) - - it('should return only immediate dependencies', () => { - const hfInstance = HyperFormula.buildFromArray([[ '1', '2', '=A1', '=B1+C1' ]]) - - const precedents = hfInstance.getCellPrecedents({ sheet: 0, col: 3, row: 0 }) - - expect(precedents).toEqual([ - { sheet: 0, col: 1, row: 0 }, - { sheet: 0, col: 2, row: 0 }, - ]) - }) - - it('should return named expressions dependencies as cell references in sheet -1', () => { - const hfInstance = HyperFormula.buildFromArray([[ '=foo' ]]) - hfInstance.addNamedExpression('foo', '=42') - - const dependents = hfInstance.getCellPrecedents({ sheet: 0, col: 0, row: 0 }) - - expect(dependents).toEqual([ - { sheet: -1, col: 0, row: 0 }, - ]) - }) - - it('should throw error if address is a malformed SimpleCellAddress', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=SUM(A1:B1)', '=SUMSQ(A1:B1)'], - ['=A2+B2'], - ]) - const malformedAddress = {col: 0} as SimpleCellAddress - expect(() => { - engine.getCellPrecedents(malformedAddress) - }).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress | SimpleCellRange', malformedAddress.toString())) - }) - - it('should correctly process cell dependencies with multiple range types', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3, 4], - [5, 6, 7, 8], - ['=SUM(A1:D1)', '=SUM(A2:D2)', '=SUM(A1:D2)', '=A1+B1'], - ]) - - expect(engine.getCellValue(adr('A3'))).toBe(10) - expect(engine.getCellValue(adr('B3'))).toBe(26) - expect(engine.getCellValue(adr('C3'))).toBe(36) - expect(engine.getCellValue(adr('D3'))).toBe(3) - }) - - it('should correctly process named expression dependencies', () => { - const engine = HyperFormula.buildFromArray([ - [42], - ['=MyValue * 2'], - ], {}, [ - {name: 'MyValue', expression: '=Sheet1!$A$1'}, - ]) - - expect(engine.getCellValue(adr('A2'))).toBe(84) - - engine.setCellContents(adr('A1'), 100) - expect(engine.getCellValue(adr('A2'))).toBe(200) - }) - }) -}) diff --git a/test/unit/graph-garbage-collection.spec.ts b/test/unit/graph-garbage-collection.spec.ts deleted file mode 100644 index c7c0aa0603..0000000000 --- a/test/unit/graph-garbage-collection.spec.ts +++ /dev/null @@ -1,350 +0,0 @@ -import {HyperFormula} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {adr} from './testUtils' - -describe('vertex counting', () => { - it('one-time formula', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'] - ]) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(4) - engine.calculateFormula('=SUM(A1:B2)', 0) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(4) - }) - - it('cruds', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'] - ]) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(4) - engine.setCellContents(adr('A1'), '=SUM(A2:B2)') - expect(engine.dependencyGraph.graph.getNodes().length).toBe(5) - engine.setCellContents(adr('A1'), 1) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(4) - }) -}) - -describe('range mapping', () => { - it('one-time formula', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'] - ]) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - engine.calculateFormula('=SUM(A1:B2)', 0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('cruds', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'] - ]) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - engine.setCellContents(adr('A1'), '=SUM(A2:B2)') - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(1) - engine.setCellContents(adr('A1'), 1) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) -}) - -function randomInteger(min: number, max: number) { - return Math.floor(Math.random() * (max - min + 1)) + min -} - -describe('larger tests', () => { - - it('large fixed', () => { - const arr = [ - [ - '=SUM(B2:C4)', - ], - [ - null, - '=SUM(A3:B3)', - ], - [ - '=SUM(B2:C3)', - ], - ] - const engine = HyperFormula.buildFromArray(arr) - for (let x = 0; x < 3; x++) { - for (let y = 0; y < 3; y++) { - engine.setCellContents({sheet: 0, col: x, row: y}, null) - } - } - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('large fixed #2', () => { - const arr = [ - [ - null, - '=SUM(A1:A2)', - '=SUM(A1:A1)', - '=SUM(A1:A2)', - ], - ] - const engine = HyperFormula.buildFromArray(arr) - engine.setCellContents({sheet: 0, col: 1, row: 0}, null) - engine.setCellContents({sheet: 0, col: 2, row: 0}, null) - engine.setCellContents({sheet: 0, col: 3, row: 0}, null) - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('large fixed #3', () => { - const arr = [ - [ - '=SUM(A1:B1)', - ], - ] - const engine = HyperFormula.buildFromArray(arr) - - engine.setCellContents({sheet: 0, col: 0, row: 0}, null) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('large fixed #4', () => { - const arr = [ - [ - null, '=SUM(A1:A1)', '=SUM(A1:A2)', '=SUM(A1:A3)', '=SUM(A1:A4)', - ], - ] - const engine = HyperFormula.buildFromArray(arr) - - engine.setCellContents({sheet: 0, col: 1, row: 0}, null) - engine.setCellContents({sheet: 0, col: 2, row: 0}, null) - engine.setCellContents({sheet: 0, col: 3, row: 0}, null) - engine.setCellContents({sheet: 0, col: 4, row: 0}, null) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('repeat the same crud', () => { - const engine = HyperFormula.buildFromArray([]) - for (let tmp = 0; tmp < 3; tmp++) { - for (let x = 0; x < 10; x++) { - for (let y = 0; y < 10; y++) { - const col1 = randomInteger(2, 7) - const row1 = randomInteger(2, 7) - const col2 = col1 + randomInteger(-2, 2) - const row2 = row1 + randomInteger(-2, 2) - const startAddress = engine.simpleCellAddressToString({ - sheet: 0, - row: Math.min(row1, row2), - col: Math.min(col1, col2) - }, 0) as string - const endAddress = engine.simpleCellAddressToString({ - sheet: 0, - row: Math.max(row1, row2), - col: Math.max(col1, col2) - }, 0) as string - const formula = '=SUM(' + startAddress + ':' + endAddress + ')' - engine.setCellContents({sheet: 0, col: x, row: y}, formula) - } - } - } - for (let x = 0; x < 10; x++) { - for (let y = 0; y < 10; y++) { - engine.setCellContents({sheet: 0, col: x, row: y}, null) - } - } - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) -}) - -describe('cruds', () => { - it('should collect empty vertices when bigger range is no longer bind to smaller range #1', () => { - const engine = HyperFormula.buildFromArray([ - [], - [], - [], - [], - ['=SUM(A1:A2)'], - ['=SUM(A1:A3)'], - ]) - - engine.removeRows(0, [0, 2]) - engine.removeRows(0, [2, 2]) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should collect empty vertices when bigger range is no longer bind to smaller range #2', () => { - const engine = HyperFormula.buildFromArray([ - [], - [], - [], - ['=SUM(A1:A2)'], - ['=SUM(A1:A3)'], - ]) - - engine.addRows(0, [2, 1]) - engine.removeRows(0, [0, 2]) - engine.removeRows(0, [2, 2]) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should collect empty vertices when bigger range is no longer bind to smaller range #3', () => { - const engine = HyperFormula.buildFromArray([ - [], - [], - [], - ['=SUM(A1:A2)'], - ['=SUM(A1:A3)'], - ]) - engine.addRows(0, [2, 1]) - - engine.removeRows(0, [4, 2]) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should collect empty vertices when bigger range is no longer bind to smaller range #4', () => { - const engine = HyperFormula.buildFromArray([ - [], - [], - [], - ['=SUM(A1:A3)'], - ['=SUM(A1:A2)'], - ]) - engine.addRows(0, [1, 1]) - - engine.setCellContents(adr('A1'), [[1], [2], [3], [4]]) - - expect(engine.getCellValue(adr('A5'))).toBe(10) - expect(engine.getCellValue(adr('A6'))).toBe(6) - - engine.removeRows(0, [0, 6]) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should collect empty vertices when bigger range is no longer bind to smaller range #5', () => { - const engine = HyperFormula.buildFromArray([ - [], - [], - [], - [], - ['=SUM(A1:A4)'], - ['=SUM(A1:A3)'], - ]) - - engine.setCellContents(adr('A1'), [[1], [2], [3], [4]]) - - expect(engine.getCellValue(adr('A5'))).toBe(10) - expect(engine.getCellValue(adr('A6'))).toBe(6) - - engine.removeRows(0, [0, 6]) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should collect empty vertices when bigger range is no longer bind to smaller range #6', () => { - const engine = HyperFormula.buildFromArray([ - [1], - [2], - [3], - [4], - ['=SUM(A1:A4)'], - ['=SUM(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A5'))).toBe(10) - expect(engine.getCellValue(adr('A6'))).toBe(6) - - engine.removeRows(0, [0, 6]) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('should collect empty vertices when bigger range is no longer bind to smaller range #7', () => { - const engine = HyperFormula.buildFromArray([ - [], - [], - [], - ['=SUM(A1:A2)', '=SUM(B1:B3)'], - ['=SUM(A1:A3)', '=SUM(B1:B2)'], - ]) - engine.addRows(0, [1, 1]) - - engine.setCellContents(adr('A1'), [[1, 1], [2, 2], [3, 3], [4, 4]]) - - expect(engine.getCellValue(adr('A5'))).toBe(6) - expect(engine.getCellValue(adr('B5'))).toBe(10) - expect(engine.getCellValue(adr('A6'))).toBe(10) - expect(engine.getCellValue(adr('B6'))).toBe(6) - - engine.removeRows(0, [0, 6]) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('column adding', () => { - const engine = HyperFormula.buildFromArray([ - [0, 0], - [0, 0], - [0, 0], - ['=SUM(A1:B2)'], - ['=SUM(A1:B3)'] - ]) - engine.addColumns(0, [1, 1]) - engine.setCellContents(adr('B3'), 1) - expect(engine.getCellSerialized(adr('A4'))).toBe('=SUM(A1:C2)') - expect(engine.getCellSerialized(adr('A5'))).toBe('=SUM(A1:C3)') - expect(engine.getCellValue(adr('A4'))).toBe(0) - expect(engine.getCellValue(adr('A5'))).toBe(1) - }) - - it('movecell', () => { - const engine = HyperFormula.buildFromArray([ - [1], - [2], - [3], - [4], - ['=SUM(A1:A3)'], - ['=SUM(A1:A4)'], - ]) - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 3), adr('B1')) - engine.setCellContents(adr('B1'), null) - engine.setCellContents(adr('B2'), null) - engine.setCellContents(adr('B3'), null) - engine.setCellContents(adr('A4'), null) - engine.setCellContents(adr('A5'), null) - engine.setCellContents(adr('A6'), null) - - expect(engine.dependencyGraph.graph.getNodes().length).toBe(0) - expect(engine.dependencyGraph.rangeMapping.getNumberOfRangesInSheet(0)).toBe(0) - }) - - it('addColumns after addRows', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2', '=SUM($A$1:A1)'], - ['3', '=SUM($A$1:A2)'], - ]) - - engine.addRows(0, [1, 1]) - engine.addColumns(0, [0, 1]) - engine.removeColumns(0, [0, 1]) - - expect(engine.getCellValue(adr('B3'))).toEqual(1) - expect(engine.getCellValue(adr('B4'))).toEqual(3) - }) -}) diff --git a/test/unit/graph-vertex.spec.ts b/test/unit/graph-vertex.spec.ts deleted file mode 100644 index fd501e776c..0000000000 --- a/test/unit/graph-vertex.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {Graph, ValueCellVertex, Vertex} from '../../src/DependencyGraph' - -const dummyGetDependenciesQuery: () => any[] = () => [] - -describe('Graph with Vertex', () => { - it('#addNodeAndReturnId works correctly with Vertex instances', () => { - const graph = new Graph(dummyGetDependenciesQuery) - - const v1 = new ValueCellVertex("1'", "1'") - const v2 = new ValueCellVertex('2', '2') - graph.addNodeAndReturnId(v1) - graph.addNodeAndReturnId(v1) - graph.addNodeAndReturnId(v2) - - expect(graph.getNodes().length).toBe(2) - }) -}) diff --git a/test/unit/graph.spec.ts b/test/unit/graph.spec.ts deleted file mode 100644 index 4408438d33..0000000000 --- a/test/unit/graph.spec.ts +++ /dev/null @@ -1,554 +0,0 @@ -import {Graph} from '../../src/DependencyGraph' -import {DependencyQuery} from '../../src/DependencyGraph/Graph' -import {graphEdgesCount} from './testUtils' - -class IdentifiableString { - constructor( - public id: number, - public str: string) { - } -} - -const dummyDependencyQuery: DependencyQuery = () => [] - -describe('Graph class', () => { - describe('addNodeAndReturnId', () => { - it('adds a node to the empty graph', () => { - const graph = new Graph(dummyDependencyQuery) - - const node = new IdentifiableString(0, 'foo') - graph.addNodeAndReturnId(node) - - expect(graph.getNodes().length).toBe(1) - }) - - it('does not add duplicate nodes', () => { - const graph = new Graph(dummyDependencyQuery) - - const node = new IdentifiableString(0, 'foo') - graph.addNodeAndReturnId(node) - graph.addNodeAndReturnId(node) - - expect(graph.getNodes().length).toBe(1) - }) - - it('keeps existing edges when dealing with duplicates', () => { - const graph = new Graph(dummyDependencyQuery) - - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - expect(graph.adjacentNodes(node0)).toEqual(new Set([])) - - graph.addEdge(node0, node1) - expect(graph.adjacentNodes(node0)).toEqual(new Set([node1])) - - graph.addNodeAndReturnId(node0) - - expect(graph.adjacentNodes(node0)).toEqual(new Set([node1])) - }) - }) - - describe('removeNode', () => { - it('removes a node if it exists', () => { - const graph = new Graph(dummyDependencyQuery) - - const node = new IdentifiableString(0, 'foo') - graph.addNodeAndReturnId(node) - graph.removeNode(node) - - expect(graph.getNodes().length).toBe(0) - }) - - it('throws error when node does not exist', () => { - const graph = new Graph(dummyDependencyQuery) - - expect(() => graph.removeNode(new IdentifiableString(0, 'foo'))).toThrowError(/Unknown node/) - }) - }) - - describe('hasNode', () => { - it('returns false when graph is empty', () => { - const graph = new Graph(dummyDependencyQuery) - - expect(graph.hasNode(new IdentifiableString(0, 'foo'))).toBe(false) - }) - - it('returns true if node exists', () => { - const graph = new Graph(dummyDependencyQuery) - - const node = new IdentifiableString(0, 'foo') - graph.addNodeAndReturnId(node) - - expect(graph.hasNode(node)).toBe(true) - }) - - it('returns false if node does not exist', () => { - const graph = new Graph(dummyDependencyQuery) - - const node = new IdentifiableString(0, 'foo') - graph.addNodeAndReturnId(node) - - expect(graph.hasNode(new IdentifiableString(1, 'foo'))).toBe(false) - }) - - it('returns false if node was removed', () => { - const graph = new Graph(dummyDependencyQuery) - - const node = new IdentifiableString(0, 'foo') - graph.addNodeAndReturnId(node) - graph.removeNode(node) - - expect(graph.hasNode(node)).toBe(false) - }) - }) - - describe('addEdge', () => { - it('does not add duplicated edges', () => { - const graph = new Graph(dummyDependencyQuery) - - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - graph.addEdge(node0, node1) - - expect(graph.adjacentNodes(node0)).toEqual(new Set([node1])) - }) - - it('throws error when the origin node is not present', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(1, 'target') - graph.addNodeAndReturnId(node) - - expect(() => { - graph.addEdge(new IdentifiableString(0, 'origin'), node) - }).toThrowError(/Unknown node/) - }) - - it('throws error when the target node is not present', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'origin') - graph.addNodeAndReturnId(node) - - expect(() => { - graph.addEdge(node, new IdentifiableString(1, 'target')) - }).toThrowError(/Unknown node/) - }) - }) - - describe('removeEdge', () => { - it('throws error when source node does not exist', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - graph.addNodeAndReturnId(node1) - - expect(() => graph.removeEdge(node0, node1)).toThrowError(/Unknown node/) - }) - - it('throws error when target node does not exist', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - graph.addNodeAndReturnId(node0) - - expect(() => graph.removeEdge(node0, node1)).toThrowError(/Unknown node/) - }) - - it('throws error when edge does not exist', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - - expect(() => graph.removeEdge(node0, node1)).toThrowError('Edge does not exist') - }) - - it('removes an edge it it exists', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - expect(graphEdgesCount(graph)).toEqual(0) - - graph.addEdge(node0, node1) - expect(graphEdgesCount(graph)).toEqual(1) - expect(graph.existsEdge(node0, node1)).toBe(true) - - graph.removeEdge(node0, node1) - expect(graphEdgesCount(graph)).toEqual(0) - expect(graph.existsEdge(node0, node1)).toBe(false) - }) - }) - - describe('existsEdge', () => { - it('returns true if edge is present in the graph', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - - expect(graph.existsEdge(node0, node1)).toBe(true) - }) - - it('returns false if edge is not present', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - - expect(graph.existsEdge(node0, node1)).toBe(false) - }) - - it('returns false if nodes are not present in the graph', () => { - const graph = new Graph(dummyDependencyQuery) - - expect(graph.existsEdge(new IdentifiableString(0, 'foo'), new IdentifiableString(1, 'bar'))).toBe(false) - }) - }) - - describe('adjacentNodes', () => { - it('returns all target nodes adjacent to the given node', () => { - const graph = new Graph(dummyDependencyQuery) - - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - - expect(graph.adjacentNodes(node0)).toEqual(new Set([node1])) - }) - - it('throws error if the source node is not present in the graph', () => { - const graph = new Graph(dummyDependencyQuery) - - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - - expect(() => graph.adjacentNodes(new IdentifiableString(42, 'baz'))).toThrowError(/Unknown node/) - }) - }) - - describe('adjacentNodesCount', () => { - it('returns number of outgoing edges from a given node', () => { - const graph = new Graph(dummyDependencyQuery) - - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - - expect(graph.adjacentNodesCount(node0)).toEqual(1) - }) - - it('throws error if the source node is not present in the graph', () => { - const graph = new Graph(dummyDependencyQuery) - - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - - expect(() => graph.adjacentNodesCount(new IdentifiableString(42, 'baz'))).toThrowError(/Unknown node/) - }) - }) - - describe('topSortWithScc', () => { - it('works for empty graph', () => { - const graph = new Graph(dummyDependencyQuery) - - expect(graph.topSortWithScc().sorted).toEqual([]) - expect(graph.topSortWithScc().cycled).toEqual([]) - }) - - it('returns isolated vertices', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'foo') - graph.addNodeAndReturnId(node) - - expect(graph.topSortWithScc().sorted).toEqual([node]) - expect(graph.topSortWithScc().cycled).toEqual([]) - }) - - it('returns vertices in order corresponding to the edge direction', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'foo') - const node1 = new IdentifiableString(1, 'bar') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node1, node0) - - expect(graph.topSortWithScc().sorted).toEqual([node1, node0]) - expect(graph.topSortWithScc().cycled).toEqual([]) - }) - - it('works for 4-edges acyclic graph', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - const node2 = new IdentifiableString(2, 'x2') - const node3 = new IdentifiableString(3, 'x3') - const node4 = new IdentifiableString(4, 'x4') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addNodeAndReturnId(node2) - graph.addNodeAndReturnId(node3) - graph.addNodeAndReturnId(node4) - graph.addEdge(node0, node2) - graph.addEdge(node1, node2) - graph.addEdge(node2, node3) - graph.addEdge(node4, node3) - - expect(graph.topSortWithScc().sorted).toEqual([node0, node1, node2, node4, node3]) - expect(graph.topSortWithScc().cycled).toEqual([]) - }) - - it('works for a graph with multiple connected components', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - const node2 = new IdentifiableString(2, 'x2') - const node3 = new IdentifiableString(3, 'x3') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addNodeAndReturnId(node2) - graph.addNodeAndReturnId(node3) - graph.addEdge(node0, node2) - graph.addEdge(node1, node3) - - expect(graph.topSortWithScc().sorted).toEqual([node0, node1, node2, node3]) - expect(graph.topSortWithScc().cycled).toEqual([]) - }) - - it('detects cycles', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - graph.addEdge(node1, node0) - - expect(graph.topSortWithScc().sorted).toEqual([]) - expect(new Set(graph.topSortWithScc().cycled)).toEqual(new Set([node0, node1])) - }) - - it('detects 1-node cycles', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = new IdentifiableString(0, 'x0') - const node1 = new IdentifiableString(1, 'x1') - const node2 = new IdentifiableString(2, 'x2') - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addNodeAndReturnId(node2) - graph.addEdge(node0, node1) - graph.addEdge(node1, node2) - graph.addEdge(node1, node1) - - expect(graph.topSortWithScc().sorted).toEqual([node0, node2]) - expect(graph.topSortWithScc().cycled).toEqual([node1]) - }) - }) - - describe('getTopSortedWithSccSubgraphFrom', () => { - it('calls the operatingFunction callback for sorted nodes', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = 'foo' - const node1 = 'bar' - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - - const operatingFunction = jasmine.createSpy().and.returnValue(true) - const onCycle = jasmine.createSpy() - - graph.getTopSortedWithSccSubgraphFrom([node0], operatingFunction, onCycle) - - expect(operatingFunction).toHaveBeenCalledTimes(1) - expect(operatingFunction.calls.argsFor(0)).toContain(node0) - }) - - it('works for graph with an edge', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = 'foo' - const node1 = 'bar' - - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - - const operatingFunction = jasmine.createSpy().and.returnValue(true) - const onCycle = jasmine.createSpy() - - graph.getTopSortedWithSccSubgraphFrom([node0], operatingFunction, onCycle) - - expect(operatingFunction).toHaveBeenCalledTimes(2) - expect(operatingFunction.calls.argsFor(0)).toContain(node0) - expect(operatingFunction.calls.argsFor(1)).toContain(node1) - }) - - it('omits nodes not reachable from the "modifiedNodes" array', () => { - const graph = new Graph(dummyDependencyQuery) - const node0 = 'foo' - const node1 = 'bar' - - graph.addNodeAndReturnId(node0) - graph.addNodeAndReturnId(node1) - graph.addEdge(node0, node1) - - const operatingFunction = jasmine.createSpy().and.returnValue(false) - const onCycle = jasmine.createSpy() - - graph.getTopSortedWithSccSubgraphFrom([node0], operatingFunction, onCycle) - - expect(operatingFunction).toHaveBeenCalledTimes(1) - expect(operatingFunction.calls.argsFor(0)).toContain(node0) - }) - - it('calls the operatingFunction for a node not included but reachable from the "modifiedNodes" array', () => { - const graph = new Graph(dummyDependencyQuery) - const nodes = ['foo', 'bar', 'baz'] - - nodes.forEach((n) => graph.addNodeAndReturnId(n)) - graph.addEdge(nodes[0], nodes[2]) - graph.addEdge(nodes[1], nodes[2]) - - const operatingFunction = jasmine.createSpy().and.callFake((node: string) => node === nodes[0]) - const onCycle = jasmine.createSpy() - - graph.getTopSortedWithSccSubgraphFrom([nodes[0], nodes[1]], operatingFunction, onCycle) - - expect(operatingFunction).toHaveBeenCalledTimes(3) - expect(operatingFunction.calls.argsFor(2)).toContain(nodes[2]) - }) - - it('calls onCycle callback for nodes that are on cycle', () => { - const graph = new Graph(dummyDependencyQuery) - const nodes = ['foo', 'c0', 'c1', 'c2'] - - nodes.forEach((n) => graph.addNodeAndReturnId(n)) - graph.addEdge(nodes[0], nodes[1]) - graph.addEdge(nodes[1], nodes[2]) - graph.addEdge(nodes[2], nodes[3]) - graph.addEdge(nodes[3], nodes[1]) - - const operatingFunction = jasmine.createSpy().and.returnValue(true) - const onCycle = jasmine.createSpy() - const cycled = graph.getTopSortedWithSccSubgraphFrom([nodes[0]], operatingFunction, onCycle).cycled - - expect(operatingFunction).toHaveBeenCalledTimes(1) - expect(onCycle).toHaveBeenCalledTimes(3) - expect(cycled).toEqual(['c0', 'c1', 'c2']) - }) - - it('does not call operatingFunction callback for nodes that are on cycle', () => { - const graph = new Graph(dummyDependencyQuery) - const nodes = ['c0', 'c1', 'c2'] - nodes.forEach((n) => graph.addNodeAndReturnId(n)) - graph.addEdge(nodes[0], nodes[1]) - graph.addEdge(nodes[1], nodes[2]) - graph.addEdge(nodes[2], nodes[0]) - - const operatingFunction = jasmine.createSpy().and.returnValue(true) - const onCycle = jasmine.createSpy() - const cycled = graph.getTopSortedWithSccSubgraphFrom([nodes[0]], operatingFunction, onCycle).cycled - - expect(operatingFunction).not.toHaveBeenCalled() - expect(cycled).toEqual(['c0', 'c1', 'c2']) - }) - - it('detects a cycle consisting of nodes not included but reachable from the "modifiedNodes" array', () => { - const graph = new Graph(dummyDependencyQuery) - const nodes = ['foo', 'c0', 'c1', 'c2'] - nodes.forEach((n) => graph.addNodeAndReturnId(n)) - graph.addEdge(nodes[0], nodes[1]) - graph.addEdge(nodes[1], nodes[2]) - graph.addEdge(nodes[2], nodes[3]) - graph.addEdge(nodes[3], nodes[1]) - - const operatingFunction = jasmine.createSpy().and.returnValue(true) - const onCycle = jasmine.createSpy() - const cycled = graph.getTopSortedWithSccSubgraphFrom([nodes[0]], operatingFunction, onCycle).cycled - - expect(operatingFunction).toHaveBeenCalledTimes(1) - expect(cycled).toEqual(['c0', 'c1', 'c2']) - }) - }) - - describe('markNodeAsVolatile', () => { - it('adds a node to volatile nodes array', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'foo') - - graph.addNodeAndReturnId(node) - graph.markNodeAsVolatile(node) - - expect(graph.getDirtyAndVolatileNodes()).toEqual([node]) - }) - - it('does nothing if node is not in a graph', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'foo') - - graph.markNodeAsVolatile(node) - expect(graph.getDirtyAndVolatileNodes()).toEqual([]) - }) - }) - - describe('markNodeAsChangingWithStructure', () => { - it('adds a node to special nodes structural changes array', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'foo') - - graph.addNodeAndReturnId(node) - graph.markNodeAsChangingWithStructure(node) - graph.markChangingWithStructureNodesAsDirty() - - expect(graph.getDirtyAndVolatileNodes()).toEqual([node]) - }) - - it('does nothing if node is not in a graph', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'foo') - - graph.markNodeAsChangingWithStructure(node) - graph.markChangingWithStructureNodesAsDirty() - - expect(graph.getDirtyAndVolatileNodes()).toEqual([]) - }) - }) - - describe('markNodeAsInfiniteRange', () => { - it('adds a node to the infinite ranges array', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'foo') - - graph.addNodeAndReturnId(node) - graph.markNodeAsInfiniteRange(node) - - expect(graph.getInfiniteRanges().map(({ node }) => node)).toEqual([node]) - }) - - it('does nothing if node is not in a graph', () => { - const graph = new Graph(dummyDependencyQuery) - const node = new IdentifiableString(0, 'foo') - - graph.markNodeAsInfiniteRange(node) - expect(graph.getInfiniteRanges()).toEqual([]) - }) - }) -}) diff --git a/test/unit/graphComparator.ts b/test/unit/graphComparator.ts deleted file mode 100644 index e9d977bced..0000000000 --- a/test/unit/graphComparator.ts +++ /dev/null @@ -1,133 +0,0 @@ -import {deepStrictEqual, equal} from 'assert' -import {CellError, HyperFormula} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {SimpleCellAddress, simpleCellAddress} from '../../src/Cell' -import { - ArrayFormulaVertex, - EmptyCellVertex, - ScalarFormulaVertex, - ParsingErrorVertex, - RangeVertex, - ValueCellVertex, - Vertex, -} from '../../src/DependencyGraph' -import {InterpreterValue} from '../../src/interpreter/InterpreterValue' -import {simpleCellAddressToString} from '../../src/parser' - -export class EngineComparator { - - constructor(private expected: HyperFormula, - private actual: HyperFormula) { - } - - public compare(): void { - const expectedNumberOfSheets = this.expected.sheetMapping.numberOfSheets({includePlaceholders: true}) - const numberOfSheets = this.actual.sheetMapping.numberOfSheets({includePlaceholders: true}) - - if (expectedNumberOfSheets !== numberOfSheets) { - throw Error(`Expected number of sheets ${expectedNumberOfSheets}, actual: ${numberOfSheets}`) - } - - this.expected.dependencyGraph.forceApplyPostponedTransformations() - this.actual.dependencyGraph.forceApplyPostponedTransformations() - - for (let sheet = 0; sheet < numberOfSheets; ++sheet) { - this.compareSheet(sheet) - } - } - - private compareSheet(sheet: number): void { - const expectedGraph = this.expected.graph - const actualGraph = this.actual.graph - - const expectedSheetName = this.expected.getSheetName(sheet) - const actualSheetName = this.actual.getSheetName(sheet) - equal(expectedSheetName, actualSheetName, `Expected sheet name '${expectedSheetName}', actual '${actualSheetName}'`) - - const expectedWidth = this.expected.addressMapping.getSheetWidth(sheet) - const expectedHeight = this.expected.addressMapping.getSheetHeight(sheet) - const actualWidth = this.actual.addressMapping.getSheetWidth(sheet) - const actualHeight = this.actual.addressMapping.getSheetHeight(sheet) - - this.compareMatrixMappings() - - for (let x = 0; x < Math.max(expectedWidth, actualWidth); ++x) { - for (let y = 0; y < Math.max(expectedHeight, actualHeight); ++y) { - const address = simpleCellAddress(sheet, x, y) - const expectedVertex = this.expected.addressMapping.getCell(address) - const actualVertex = this.actual.addressMapping.getCell(address) - if (expectedVertex === undefined && actualVertex === undefined) { - continue - } else if ( - (expectedVertex instanceof ScalarFormulaVertex && actualVertex instanceof ScalarFormulaVertex) || - (expectedVertex instanceof ArrayFormulaVertex && actualVertex instanceof ArrayFormulaVertex) - ) { - const actualVertexAddress = actualVertex.getAddress(this.actual.dependencyGraph.lazilyTransformingAstService) - const expectedVertexAddress = expectedVertex.getAddress(this.expected.dependencyGraph.lazilyTransformingAstService) - deepStrictEqual(actualVertexAddress, expectedVertexAddress, `Different addresses in formulas. expected: ${actualVertexAddress}, actual: ${expectedVertexAddress}`) - deepStrictEqual(actualVertex.getFormula(this.actual.lazilyTransformingAstService), expectedVertex.getFormula(this.expected.lazilyTransformingAstService), 'Different AST in formulas') - deepStrictEqual(this.normalizeCellValue(actualVertex.getCellValue()), this.normalizeCellValue(expectedVertex.getCellValue()), `Different values of formulas. expected: ${expectedVertex.getCellValue().toString()}, actual: ${actualVertex.getCellValue().toString()}`) - } else if (expectedVertex instanceof ValueCellVertex && actualVertex instanceof ValueCellVertex) { - deepStrictEqual(actualVertex.getCellValue(), expectedVertex.getCellValue(), `Different values. expected: ${expectedVertex.getCellValue().toString()}, actual: ${actualVertex.getCellValue().toString()}`) - } else if (expectedVertex instanceof EmptyCellVertex && actualVertex instanceof EmptyCellVertex) { - continue - } else if (expectedVertex instanceof ParsingErrorVertex && actualVertex instanceof ParsingErrorVertex) { - deepStrictEqual(expectedVertex.rawInput, actualVertex.rawInput, `Different raw input. expected: ${expectedVertex.rawInput}, actual: ${actualVertex.rawInput}`) - } else { - throw Error('Different vertex types') - } - - const expectedAdjacentAddresses = new Set() - const actualAdjacentAddresses = new Set() - - for (const adjacentNode of expectedGraph.adjacentNodes(expectedVertex)) { - expectedAdjacentAddresses.add(this.getAddressOfVertex(this.expected, adjacentNode)) - } - for (const adjacentNode of actualGraph.adjacentNodes(actualVertex)) { - actualAdjacentAddresses.add(this.getAddressOfVertex(this.actual, adjacentNode)) - } - const sheetMapping = this.expected.sheetMapping - deepStrictEqual(actualAdjacentAddresses, expectedAdjacentAddresses, `Dependent vertices of ${ - simpleCellAddressToString(sheetMapping.getSheetName.bind(sheetMapping), address, 0) ?? 'ERROR' - } (Sheet '${sheetMapping.getSheetName(address.sheet) ?? 'Unknown sheet'}') are not same`) - } - } - } - - private normalizeCellValue(value: InterpreterValue): any { - if (value instanceof CellError) { - return { - type: value.type, - message: value.message, - root: (value.root as any)?.cellAddress - } - } - return value - } - - private compareMatrixMappings() { - const actual = this.actual.arrayMapping.arrayMapping - const expected = this.expected.arrayMapping.arrayMapping - - expect(actual.size).toEqual(expected.size) - - for (const [key, value] of expected.entries()) { - - const actualEntry = actual.get(key)! - expect(actualEntry).toBeDefined() - expect(actualEntry.array.size.isRef).toBe(value.array.size.isRef) - } - } - - private getAddressOfVertex(engine: HyperFormula, vertex: Vertex): SimpleCellAddress | AbsoluteCellRange { - if (vertex instanceof RangeVertex) { - return vertex.range - } - for (const [address, v] of engine.addressMapping.entries()) { - if (v === vertex) { - return address - } - } - throw Error('No such vertex in address mapping: ') - } -} diff --git a/test/unit/helpers/licenseKeyValidator.spec.ts b/test/unit/helpers/licenseKeyValidator.spec.ts deleted file mode 100644 index bfcad8c48f..0000000000 --- a/test/unit/helpers/licenseKeyValidator.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {HyperFormula} from '../../../src' -import {LicenseKeyValidityState} from '../../../src/helpers/licenseKeyValidator' - -describe('license key', () => { - describe('valid key', () => { - it('should verify "gpl-v3" as a valid license key', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: 'gpl-v3', - }) - - expect(hf.licenseKeyValidityState).toEqual(LicenseKeyValidityState.VALID) - }) - - it('should verify "internal-use-in-handsontable" as a valid license key', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: 'internal-use-in-handsontable', - }) - - expect(hf.licenseKeyValidityState).toEqual(LicenseKeyValidityState.VALID) - }) - }) - - describe('invalid key', () => { - it('should verify "gpl" as an invalid license key', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: 'gpl-v1', - }) - - expect(hf.licenseKeyValidityState).toEqual(LicenseKeyValidityState.INVALID) - }) - - it('should verify license keys correctnes', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: '11111-11111-11111-11111-11111', - }) - - expect(hf.licenseKeyValidityState).toEqual(LicenseKeyValidityState.INVALID) - }) - }) - - describe('missing key', () => { - it('should verify an empty string as an invalid license key', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: '', - }) - - expect(hf.licenseKeyValidityState).toEqual(LicenseKeyValidityState.MISSING) - }) - }) - - describe('expired key', () => { - it('should verify that key is expired', () => { - const hf = HyperFormula.buildEmpty({ - licenseKey: '80584-cc272-2e7c4-06f16-4db00', - }) - - expect(hf.licenseKeyValidityState).toEqual(LicenseKeyValidityState.EXPIRED) - }) - }) -}) diff --git a/test/unit/i18n.spec.ts b/test/unit/i18n.spec.ts deleted file mode 100644 index 8ad8370a0d..0000000000 --- a/test/unit/i18n.spec.ts +++ /dev/null @@ -1,194 +0,0 @@ -import {ErrorType, HyperFormula, LanguageAlreadyRegisteredError, LanguageNotRegisteredError} from '../../src' -import {ProtectedFunctionTranslationError} from '../../src' -import {ErrorTranslationSet, RawTranslationPackage, TranslationPackage} from '../../src/i18n' -import * as languages from '../../src/i18n/languages' -import {enGB, plPL, enUS} from '../../src/i18n/languages' -import {FunctionRegistry} from '../../src/interpreter/FunctionRegistry' -import {CellAddress} from '../../src/parser' -import {adr, extractReference} from './testUtils' -import {MissingTranslationError} from '../../src/errors' - -describe('i18n', () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const allLanguages: RawTranslationPackage[] = Object.getOwnPropertyNames(languages).filter(lang => !lang.startsWith('_')).map(lang => languages[lang]) - - beforeEach(() => { - HyperFormula.registerLanguage('plPL', plPL) - }) - - it('using functions in different languages', () => { - const enginePL = HyperFormula.buildFromArray([ - ['=SUMA(42)'], - ], {language: 'plPL'}) - const engineEN = HyperFormula.buildFromArray([ - ['=SUM(42)'], - ], {language: 'enGB'}) - - expect(enginePL.getCellValue(adr('A1'))).toBe(42) - expect(engineEN.getCellValue(adr('A1'))).toBe(42) - }) - - it('using functions in different languages with not standard characters', () => { - const enginePL = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['2'], - ['=LICZ.JEŻELI(A1:A3, ">=1")'], - ], {language: 'plPL'}) - const engineEN = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['2'], - ['=COUNTIF(A1:A3, ">=1")'], - ], {language: 'enGB'}) - - expect(enginePL.getCellValue(adr('A4'))).toBe(2) - expect(engineEN.getCellValue(adr('A4'))).toBe(2) - }) - - it('translation works for parser hardcoded offset procedure', () => { - const enginePL = HyperFormula.buildFromArray([ - ['=PRZESUNIĘCIE(A1, 1, 1)'], - ], {language: 'plPL'}) - const engineEN = HyperFormula.buildFromArray([ - ['=OFFSET(A1, 1, 1)'], - ]) - - expect(extractReference(enginePL, adr('A1'))).toEqual(CellAddress.relative(1, 1)) - expect(extractReference(engineEN, adr('A1'))).toEqual(CellAddress.relative(1, 1)) - }) - - it('all function translation keys has to be upper cased', () => { - for (const lang of Object.getOwnPropertyNames(languages)) { - if (!lang.startsWith('_')) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const translationPackage = languages[lang] - for (const translationKey in translationPackage.functions) { - expect(translationPackage.functions[translationKey]).toEqual(translationPackage.functions[translationKey].toUpperCase()) - } - } - } - }) - - it('all translation packages should not include protected function definition', () => { - allLanguages.forEach(lang => { - const translatedFunctionsInLang = new Set(Object.keys(lang.functions)) - expect(translatedFunctionsInLang.has('VERSION')).toEqual(false) - }) - }) - - it('all translation packages should translate all implemented functions', () => { - const implementedFunctions = new Set(Array.from(FunctionRegistry.getRegisteredFunctionIds())) - - allLanguages.forEach(lang => { - const translatedFunctionsInLang = new Set(Object.keys(lang.functions)) - translatedFunctionsInLang.add('VERSION') /* missing protected function */ - expect(translatedFunctionsInLang).toEqual(implementedFunctions) - }) - }) - - it('functions should have unique names in a single language', () => { - allLanguages.forEach(lang => { - const names = Object.values(lang.functions) - names.sort() - for (let i = 0; i < names.length - 1; i++) { - expect(names[i]).not.toEqual(names[i + 1]) - } - }) - }) - - it('translation package sanitization', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => new TranslationPackage({}, {}, {})).toThrowError() - }) - - it('should not be possible to construct TranslationPackage with protected translation', () => { - expect(() => - new TranslationPackage({'VERSION': 'FOO'}, plPL.errors, plPL.ui) - ).toThrow(new ProtectedFunctionTranslationError('VERSION')) - }) - - it('should not be possible to construct TranslationPackage with untranslated memebrs of Error Type', () => { - const unknownErrorType = ErrorType.SPILL as string - const errorsMap: Record = {} - for (const key of Object.values(ErrorType)) { - errorsMap[key] = ErrorType[key] - } - delete errorsMap[unknownErrorType] - expect(() => - new TranslationPackage(plPL.functions, errorsMap as ErrorTranslationSet, plPL.ui) - ).toThrow(new MissingTranslationError(`errors.${unknownErrorType}`)) - }) - - it('should not be possible to extend TranslationPackage with protected translation', () => { - const translationPackage = HyperFormula.getLanguage('plPL') - expect(() => - translationPackage.extendFunctions({'VERSION': 'FOO'}) - ).toThrow(new ProtectedFunctionTranslationError('VERSION')) - }) - - it('should not be possible to register language with protected translation', () => { - const rawTranslationPackage: RawTranslationPackage = { - ...plPL, - functions: {'VERSION': 'FOO'} - } - - expect(() => - HyperFormula.registerLanguage('foo', rawTranslationPackage) - ).toThrow(new ProtectedFunctionTranslationError('VERSION')) - }) - - it('should throw error when trying to register same language twice', () => { - expect(() => - HyperFormula.registerLanguage('plPL', plPL) - ).toThrow(new LanguageAlreadyRegisteredError()) - }) - - it('should throw error when trying to unregister not registered language', () => { - expect(() => - HyperFormula.unregisterLanguage('foo') - ).toThrow(new LanguageNotRegisteredError()) - }) - - it('should throw error when trying to retrieve not registered language', () => { - expect(() => - HyperFormula.getLanguage('foo') - ).toThrow(new LanguageNotRegisteredError()) - }) - - it('`languages` static property should contain only default enGB language when using ES module', () => { - expect(Object.keys(HyperFormula.languages)).toEqual(['enGB']) - }) - - describe('language "enUS"', () => { - it('should be available', () => { - HyperFormula.registerLanguage('enUS', enUS) - const engineUS = HyperFormula.buildFromArray([['=SUM(42)']], { language: 'enUS' }) - - expect(engineUS.getCellValue(adr('A1'))).toBe(42) - }) - - it('should langCode = "enUS"', () => { - expect(enUS.langCode).toEqual('enUS') - }) - - it('should have the same translations as "enGB"', () => { - const allFunctions = Object.keys(enGB.functions) - const areAllTranslationsTheSame = allFunctions.every(key => enGB.functions[key] === enUS.functions[key]) - - expect(areAllTranslationsTheSame).toBeTruthy() - }) - }) - - describe('registerLanguage', () => { - it('should throw error when language code is not a string', () => { - expect(() => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - HyperFormula.registerLanguage(42 as any, enGB) - }).toThrowError('Expected value of type: string for config parameter: languageCode') - }) - }) -}) diff --git a/test/unit/interpreter.spec.ts b/test/unit/interpreter.spec.ts deleted file mode 100644 index 96b8630efc..0000000000 --- a/test/unit/interpreter.spec.ts +++ /dev/null @@ -1,348 +0,0 @@ -import {HyperFormula} from '../../src' -import {ErrorType} from '../../src/Cell' -import {ErrorMessage} from '../../src/error-message' -import {adr, detailedError} from './testUtils' - -describe('Interpreter', () => { - it('relative addressing formula', () => { - const engine = HyperFormula.buildFromArray([['42', '=A1']]) - - expect(engine.getCellValue(adr('B1'))).toBe(42) - }) - - it('number literal', () => { - const engine = HyperFormula.buildFromArray([['3']]) - - expect(engine.getCellValue(adr('A1'))).toBe(3) - }) - - it('negative number literal', () => { - const engine = HyperFormula.buildFromArray([['=-3']]) - - expect(engine.getCellValue(adr('A1'))).toBe(-3) - }) - - it('negative number literal - non numeric value', () => { - const engine = HyperFormula.buildFromArray([['=-"foo"']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('string literals - faulty tests', () => { - const engine = HyperFormula.buildFromArray([ - ['www', '1www', 'www1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe('www') - expect(engine.getCellValue(adr('B1'))).toBe('1www') - expect(engine.getCellValue(adr('C1'))).toBe('www1') - }) - - it('string literals in formula - faulty tests', () => { - const engine = HyperFormula.buildFromArray([ - ['="www"', '="1www"', '="www1"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe('www') - expect(engine.getCellValue(adr('B1'))).toBe('1www') - expect(engine.getCellValue(adr('C1'))).toBe('www1') - }) - - it('ranges - VALUE error when evaluating without context', () => { - const engine = HyperFormula.buildFromArray([['1'], ['2'], ['=A1:A2']]) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('procedures - SUM with bad args', () => { - const engine = HyperFormula.buildFromArray([['=SUM(B1)', 'asdf']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('procedures - not known procedure', () => { - const engine = HyperFormula.buildFromArray([['=FOO()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOO'))) - }) - - it('errors - parsing errors', () => { - const engine = HyperFormula.buildFromArray([['=1A1', '=foo(', '=)(asdf']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('function OFFSET basic use', () => { - const engine = HyperFormula.buildFromArray([['5', '=OFFSET(B1, 0, -1)', '=OFFSET(A1, 0, 0)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual(5) - expect(engine.getCellValue(adr('C1'))).toEqual(5) - }) - - it('function OFFSET out of range', () => { - const engine = HyperFormula.buildFromArray([['=OFFSET(A1, -1, 0)', '=OFFSET(A1, 0, -1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.OutOfSheet)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.OutOfSheet)) - }) - - it('function OFFSET returns bigger range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(OFFSET(A1, 0, 1,2,1))', '5', '6'], - ['2', '3', '4'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(8) - }) - - it('function OFFSET returns rectangular range and fails', () => { - const engine = HyperFormula.buildFromArray([ - ['=OFFSET(A1, 0, 1,2,1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('function OFFSET used twice in a range', () => { - const engine = HyperFormula.buildFromArray([ - ['5', '6', '=SUM(OFFSET(A2,-1,0):OFFSET(A2,0,1))'], - ['2', '3', '4'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(16) - }) - - it('function OFFSET as a reference inside SUM', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '0', '10'], - ['5', '6', '=SUM(SUM(OFFSET(C2,-1,0),A2),-B2)'], - ]) - - expect(engine.getCellValue(adr('C2'))).toEqual(9) - }) - - it('initializing engine with multiple sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['0', '1'], - ['2', '3'], - ], - Sheet2: [ - ['=SUM(Sheet1!A1:Sheet1!B2)'], - ], - }) - expect(engine.getCellValue(adr('A1', 1))).toEqual(6) - }) - - it('using bad range reference', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['0', '1'], - ['2', '3'], - ], - Sheet2: [ - ['=SUM(Sheet1!A1:Sheet2!A2)'], - [''], - ], - }) - expect(engine.getCellValue(adr('A1', 1))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.RangeManySheets)) - }) - - it('expression with parenthesis', () => { - const engine = HyperFormula.buildFromArray([ - ['=(1+2)*3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(9) - }) - - it('should return #REF when range is pointing to multiple sheets', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [ - ['=SUM(Sheet1!A2:Sheet2!B3)'], - ['=SUM(Sheet1!A:Sheet2!B)'], - ['=SUM(Sheet1!2:Sheet2!3)'], - ['=Sheet1!A2:Sheet2!B3'], - ['=Sheet1!A:Sheet2!B'], - ['=Sheet1!2:Sheet2!3'], - ], - 'Sheet2': [] - }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.RangeManySheets)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.RangeManySheets)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.RangeManySheets)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.RangeManySheets)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.RangeManySheets)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.RangeManySheets)) - }) - - it('should return #REF when referencing non-existing sheet - just cell reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=NonExistingSheet!A1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - cell reference inside a formula', () => { - const engine = HyperFormula.buildFromArray([ - ['=ABS(NonExistingSheet!A1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - cell reference inside a numeric aggregation formula', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(NonExistingSheet!A1, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - cell range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(NonExistingSheet!C4:F16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - cell range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(NonExistingSheet!C4:F16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - row range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(NonExistingSheet!1:2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - row range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(NonExistingSheet!1:2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - column range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(NonExistingSheet!A:B)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when referencing non-existing sheet - column range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(NonExistingSheet!A:B)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range starts with non-existing sheet - cell range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(NonExistingSheet!A1:Sheet1!B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range starts with non-existing sheet - cell range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(NonExistingSheet!A1:Sheet1!B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range ends with non-existing sheet - cell range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(Sheet1!A1:NonExistingSheet!B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range ends with non-existing sheet - cell range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(Sheet1!A1:NonExistingSheet!B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range starts with non-existing sheet - row range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(NonExistingSheet!1:Sheet1!2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range starts with non-existing sheet - row range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(NonExistingSheet!1:Sheet1!2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range ends with non-existing sheet - row range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(Sheet1!1:NonExistingSheet!2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range ends with non-existing sheet - row range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(Sheet1!1:NonExistingSheet!2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range starts with non-existing sheet - column range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(NonExistingSheet!A:Sheet1!B)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range starts with non-existing sheet - column range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(NonExistingSheet!A:Sheet1!B)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range ends with non-existing sheet - column range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(Sheet1!A:NonExistingSheet!B)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) - - it('should return #REF when range ends with non-existing sheet - column range - numeric aggregation function', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(Sheet1!A:NonExistingSheet!B)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF)) - }) -}) diff --git a/test/unit/interpreter/aggregation-arguments.spec.ts b/test/unit/interpreter/aggregation-arguments.spec.ts deleted file mode 100644 index 52fb28462c..0000000000 --- a/test/unit/interpreter/aggregation-arguments.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('AVERAGE function', () => { - it('should work for empty arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(1,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) - - it('should work for empty reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(A2,B2)'], - [1, null] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should work for range with empty val', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(A2:B2)'], - [1, null] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should work for empty reference + empty arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(A2,B2,)'], - [1, null] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) - - it('should work for range with empty val + empty arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(A2:B2,)'], - [1, null] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) - - it('should work for coercible arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(2,TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1.5) - }) - - it('should work for coercible value in reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(A2,B2)'], - [2, true] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('should work for coercible value in range', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(A2:B2)'], - [2, true] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/aliases.spec.ts b/test/unit/interpreter/aliases.spec.ts deleted file mode 100644 index 7a5627d2aa..0000000000 --- a/test/unit/interpreter/aliases.spec.ts +++ /dev/null @@ -1,208 +0,0 @@ -import {HyperFormula} from '../../../src' - -describe('Function aliases', () => { - const engine = HyperFormula.buildEmpty() - it('NEGBINOMDIST should be an alias of NEGBINOM.DIST', () => { - expect(engine.getFunctionPlugin('NEGBINOMDIST')!.aliases!['NEGBINOMDIST']).toEqual('NEGBINOM.DIST') - }) - - it('BETADIST should be an alias of BETA.DIST', () => { - expect(engine.getFunctionPlugin('BETADIST')!.aliases!['BETADIST']).toEqual('BETA.DIST') - }) - - it('EXPONDIST should be an alias of EXPON.DIST', () => { - expect(engine.getFunctionPlugin('EXPONDIST')!.aliases!['EXPONDIST']).toEqual('EXPON.DIST') - }) - - it('NORMDIST should be an alias of NORM.DIST', () => { - expect(engine.getFunctionPlugin('NORMDIST')!.aliases!['NORMDIST']).toEqual('NORM.DIST') - }) - - it('NORMINV should be an alias of NORM.INV', () => { - expect(engine.getFunctionPlugin('NORMINV')!.aliases!['NORMINV']).toEqual('NORM.INV') - }) - - it('NORMSDIST should be an alias of NORM.S.DIST', () => { - expect(engine.getFunctionPlugin('NORMSDIST')!.aliases!['NORMSDIST']).toEqual('NORM.S.DIST') - }) - - it('NORMSINV should be an alias of NORM.S.INV', () => { - expect(engine.getFunctionPlugin('NORMSINV')!.aliases!['NORMSINV']).toEqual('NORM.S.INV') - }) - - it('LOGINV should be an alias of LOGNORM.INV', () => { - expect(engine.getFunctionPlugin('LOGINV')!.aliases!['LOGINV']).toEqual('LOGNORM.INV') - }) - - it('LOGNORMDIST should be an alias of LOGNORM.DIST', () => { - expect(engine.getFunctionPlugin('LOGNORMDIST')!.aliases!['LOGNORMDIST']).toEqual('LOGNORM.DIST') - }) - - it('TINV should be an alias of T.INV.2T', () => { - expect(engine.getFunctionPlugin('TINV')!.aliases!['TINV']).toEqual('T.INV.2T') - }) - - it('HYPGEOMDIST should be an alias of HYPGEOM.DIST', () => { - expect(engine.getFunctionPlugin('HYPGEOMDIST')!.aliases!['HYPGEOMDIST']).toEqual('HYPGEOM.DIST') - }) - - it('POISSON should be an alias of POISSON.DIST', () => { - expect(engine.getFunctionPlugin('POISSON')!.aliases!['POISSON']).toEqual('POISSON.DIST') - }) - - it('WEIBULL should be an alias of WEIBULL.DIST', () => { - expect(engine.getFunctionPlugin('WEIBULL')!.aliases!['WEIBULL']).toEqual('WEIBULL.DIST') - }) - - it('FINV should be an alias of F.INV.RT', () => { - expect(engine.getFunctionPlugin('FINV')!.aliases!['FINV']).toEqual('F.INV.RT') - }) - - it('FDIST should be an alias of F.DIST.RT', () => { - expect(engine.getFunctionPlugin('FDIST')!.aliases!['FDIST']).toEqual('F.DIST.RT') - }) - - it('CHIDIST should be an alias of CHISQ.DIST.RT', () => { - expect(engine.getFunctionPlugin('CHIDIST')!.aliases!['CHIDIST']).toEqual('CHISQ.DIST.RT') - }) - - it('CHIINV should be an alias of CHISQ.INV.RT', () => { - expect(engine.getFunctionPlugin('CHIINV')!.aliases!['CHIINV']).toEqual('CHISQ.INV.RT') - }) - - it('GAMMADIST should be an alias of GAMMA.DIST', () => { - expect(engine.getFunctionPlugin('GAMMADIST')!.aliases!['GAMMADIST']).toEqual('GAMMA.DIST') - }) - - it('GAMMALN.PRECISE should be an alias of GAMMALN', () => { - expect(engine.getFunctionPlugin('GAMMALN.PRECISE')!.aliases!['GAMMALN.PRECISE']).toEqual('GAMMALN') - }) - - it('GAMMAINV should be an alias of GAMMA.INV', () => { - expect(engine.getFunctionPlugin('GAMMAINV')!.aliases!['GAMMAINV']).toEqual('GAMMA.INV') - }) - - it('BETAINV should be an alias of BETA.INV', () => { - expect(engine.getFunctionPlugin('BETAINV')!.aliases!['BETAINV']).toEqual('BETA.INV') - }) - - it('BINOMDIST should be an alias of BINOM.DIST', () => { - expect(engine.getFunctionPlugin('BINOMDIST')!.aliases!['BINOMDIST']).toEqual('BINOM.DIST') - }) - - it('STDEV should be an alias of STDEV.S', () => { - expect(engine.getFunctionPlugin('STDEV')!.aliases!['STDEV']).toEqual('STDEV.S') - }) - - it('STDEVP should be an alias of STDEV.P', () => { - expect(engine.getFunctionPlugin('STDEVP')!.aliases!['STDEVP']).toEqual('STDEV.P') - }) - - it('VAR should be an alias of VAR.S', () => { - expect(engine.getFunctionPlugin('VAR')!.aliases!['VAR']).toEqual('VAR.S') - }) - - it('VARP should be an alias of VAR.P', () => { - expect(engine.getFunctionPlugin('VARP')!.aliases!['VARP']).toEqual('VAR.P') - }) - - it('CONFIDENCE should be an alias of CONFIDENCE.NORM', () => { - expect(engine.getFunctionPlugin('CONFIDENCE')!.aliases!['CONFIDENCE']).toEqual('CONFIDENCE.NORM') - }) - - it('COVAR should be an alias of COVARIANCE.P', () => { - expect(engine.getFunctionPlugin('COVAR')!.aliases!['COVAR']).toEqual('COVARIANCE.P') - }) - - it('CRITBINOM should be an alias of BINOM.INV', () => { - expect(engine.getFunctionPlugin('CRITBINOM')!.aliases!['CRITBINOM']).toEqual('BINOM.INV') - }) - - it('FTEST should be an alias of F.TEST', () => { - expect(engine.getFunctionPlugin('FTEST')!.aliases!['FTEST']).toEqual('F.TEST') - }) - - it('PEARSON should be an alias of CORREL', () => { - expect(engine.getFunctionPlugin('PEARSON')!.aliases!['PEARSON']).toEqual('CORREL') - }) - - it('ZTEST should be an alias of Z.TEST', () => { - expect(engine.getFunctionPlugin('ZTEST')!.aliases!['ZTEST']).toEqual('Z.TEST') - }) - - it('WEIBULLDIST should be an alias of WEIBULL.DIST', () => { - expect(engine.getFunctionPlugin('WEIBULLDIST')!.aliases!['WEIBULLDIST']).toEqual('WEIBULL.DIST') - }) - - it('VARS should be an alias of VAR.S', () => { - expect(engine.getFunctionPlugin('VARS')!.aliases!['VARS']).toEqual('VAR.S') - }) - - it('TINV2T should be an alias of T.INV.2T', () => { - expect(engine.getFunctionPlugin('TINV2T')!.aliases!['TINV2T']).toEqual('T.INV.2T') - }) - - it('TDISTRT should be an alias of T.DIST.RT', () => { - expect(engine.getFunctionPlugin('TDISTRT')!.aliases!['TDISTRT']).toEqual('T.DIST.RT') - }) - - it('TDIST2T should be an alias of T.DIST.2T', () => { - expect(engine.getFunctionPlugin('TDIST2T')!.aliases!['TDIST2T']).toEqual('T.DIST.2T') - }) - - it('STDEVS should be an alias of STDEV.S', () => { - expect(engine.getFunctionPlugin('STDEVS')!.aliases!['STDEVS']).toEqual('STDEV.S') - }) - - it('FINVRT should be an alias of F.INV.RT', () => { - expect(engine.getFunctionPlugin('FINVRT')!.aliases!['FINVRT']).toEqual('F.INV.RT') - }) - - it('FDISTRT should be an alias of F.DIST.RT', () => { - expect(engine.getFunctionPlugin('FDISTRT')!.aliases!['FDISTRT']).toEqual('F.DIST.RT') - }) - - it('CHIDISTRT should be an alias of CHISQ.DIST.RT', () => { - expect(engine.getFunctionPlugin('CHIDISTRT')!.aliases!['CHIDISTRT']).toEqual('CHISQ.DIST.RT') - }) - - it('CHIINVRT should be an alias of CHISQ.INV.RT', () => { - expect(engine.getFunctionPlugin('CHIINVRT')!.aliases!['CHIINVRT']).toEqual('CHISQ.INV.RT') - }) - - it('COVARIANCEP should be an alias of COVARIANCE.P', () => { - expect(engine.getFunctionPlugin('COVARIANCEP')!.aliases!['COVARIANCEP']).toEqual('COVARIANCE.P') - }) - - it('COVARIANCES should be an alias of COVARIANCE.S', () => { - expect(engine.getFunctionPlugin('COVARIANCES')!.aliases!['COVARIANCES']).toEqual('COVARIANCE.S') - }) - - it('LOGNORMINV should be an alias of LOGNORM.INV', () => { - expect(engine.getFunctionPlugin('LOGNORMINV')!.aliases!['LOGNORMINV']).toEqual('LOGNORM.INV') - }) - - it('POISSONDIST should be an alias of POISSON.DIST', () => { - expect(engine.getFunctionPlugin('POISSONDIST')!.aliases!['POISSONDIST']).toEqual('POISSON.DIST') - }) - - it('SKEWP should be an alias of SKEW.P', () => { - expect(engine.getFunctionPlugin('SKEWP')!.aliases!['SKEWP']).toEqual('SKEW.P') - }) - - it('TTEST should be an alias of T.TEST', () => { - expect(engine.getFunctionPlugin('TTEST')!.aliases!['TTEST']).toEqual('T.TEST') - }) - - it('CHITEST should be an alias of CHISQ.TEST', () => { - expect(engine.getFunctionPlugin('CHITEST')!.aliases!['CHITEST']).toEqual('CHISQ.TEST') - }) - - it('ISO.CEILING should be an alias of CEILING.PRECISE', () => { - expect(engine.getFunctionPlugin('ISO.CEILING')!.aliases!['ISO.CEILING']).toEqual('CEILING.PRECISE') - }) - - it('TRUNC should be an alias of ROUNDDOWN', () => { - expect(engine.getFunctionPlugin('TRUNC')!.aliases!['TRUNC']).toEqual('ROUNDDOWN') - }) -}) diff --git a/test/unit/interpreter/binary-search.spec.ts b/test/unit/interpreter/binary-search.spec.ts deleted file mode 100644 index 2fb5df89e0..0000000000 --- a/test/unit/interpreter/binary-search.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import {compare, findLastOccurrenceInOrderedArray} from '../../../src/interpreter/binarySearch' -import {EmptyValue} from '../../../src/interpreter/InterpreterValue' -import {CellError, ErrorType} from '../../../src' - -describe('findLastOccurrenceInOrderedArray', () => { - it('returns -1 when empty array', () => { - const values: number[] = [] - expect(findLastOccurrenceInOrderedArray(1, values)).toBe(-1) - }) - - it('works for one element', () => { - const values: number[] = [1] - expect(findLastOccurrenceInOrderedArray(1, values)).toBe(0) - }) - - it('returns -1 when all elements are greater', () => { - const values: number[] = [3, 5, 10] - expect(findLastOccurrenceInOrderedArray(1, values)).toBe(-1) - }) - - it('finds index of element in values of odd length', () => { - const values: number[] = [3, 5, 10] - expect(findLastOccurrenceInOrderedArray(3, values)).toBe(0) - expect(findLastOccurrenceInOrderedArray(5, values)).toBe(1) - expect(findLastOccurrenceInOrderedArray(10, values)).toBe(2) - }) - - it('finds index of element in values of even length', () => { - const values: number[] = [3, 5, 10, 11] - expect(findLastOccurrenceInOrderedArray(3, values)).toBe(0) - expect(findLastOccurrenceInOrderedArray(5, values)).toBe(1) - expect(findLastOccurrenceInOrderedArray(10, values)).toBe(2) - expect(findLastOccurrenceInOrderedArray(11, values)).toBe(3) - }) - - it('finds index of lower bound', () => { - const values: number[] = [1, 2, 3, 7] - expect(findLastOccurrenceInOrderedArray(5, values)).toBe(2) - expect(findLastOccurrenceInOrderedArray(10, values)).toBe(3) - }) - - it('works for strings', () => { - const values: string[] = ['aaaa', 'bar', 'foo', 'xyz'] - expect(findLastOccurrenceInOrderedArray('foo', values)).toBe(2) - }) - - it('works for bools', () => { - const values: boolean[] = [false, false, false, true, true] - expect(findLastOccurrenceInOrderedArray(true, values)).toBe(4) - }) - - it('works for different types in array', () => { - const values = [3, 5, 7, 'aaaa', 'bar', 'foo', false, false, true] - expect(findLastOccurrenceInOrderedArray(5, values)).toBe(1) - expect(findLastOccurrenceInOrderedArray('foo', values)).toBe(5) - expect(findLastOccurrenceInOrderedArray(false, values)).toBe(7) - expect(findLastOccurrenceInOrderedArray(10, values)).toBe(2) - expect(findLastOccurrenceInOrderedArray('xyz', values)).toBe(5) - }) - - it('returns the last occurrence', () => { - const values = [1, 2, 2, 2, 2, 2, 3, 3, 3] - expect(findLastOccurrenceInOrderedArray(2, values)).toBe(5) - }) - - it('works for arrays ordered descending', () => { - const values: number[] = [11, 10, 5, 3] - expect(findLastOccurrenceInOrderedArray(3, values, 'desc')).toBe(3) - expect(findLastOccurrenceInOrderedArray(5, values, 'desc')).toBe(2) - expect(findLastOccurrenceInOrderedArray(10, values, 'desc')).toBe(1) - expect(findLastOccurrenceInOrderedArray(11, values, 'desc')).toBe(0) - }) -}) - -describe('compare', () => { - it('number < string', () => { - expect(compare(42, 'foobar')).toBe(-1) - expect(compare('foobar', 42)).toBe(1) - }) - - it('number < boolean', () => { - expect(compare(42, false)).toBe(-1) - expect(compare(false, 42)).toBe(1) - }) - - it('string < boolean', () => { - expect(compare('foobar', false)).toBe(-1) - expect(compare(false, 'foobar')).toBe(1) - }) - - it('numbers', () => { - expect(compare(1, 2)).toBe(-1) - expect(compare(2, 2)).toBe(0) - expect(compare(3, 2)).toBe(1) - }) - - it('bool', () => { - expect(compare(false, true)).toBe(-1) - expect(compare(true, true)).toBe(0) - expect(compare(true, false)).toBe(1) - }) - - it('string', () => { - expect(compare('a', 'b')).toBe(-1) - expect(compare('a', 'a')).toBe(0) - expect(compare('b', 'a')).toBe(1) - }) - - it('string length', () => { - expect(compare('a', 'aa')).toBe(-1) - }) - - it('empty value', () => { - expect(compare(EmptyValue, EmptyValue)).toBe(0) - expect(compare(EmptyValue, 'foo')).toBe(-1) - expect(compare('foo', EmptyValue)).toBe(1) - }) - - it('error', () => { - expect(compare('foo', new CellError(ErrorType.DIV_BY_ZERO))).toBe(-1) - }) -}) diff --git a/test/unit/interpreter/boolean-operators.spec.ts b/test/unit/interpreter/boolean-operators.spec.ts deleted file mode 100644 index 16cec42b89..0000000000 --- a/test/unit/interpreter/boolean-operators.spec.ts +++ /dev/null @@ -1,340 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - Boolean operators', () => { - it('Equals operator - numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=1=2', '=1=1', '=1+2=3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('Equals operator - strings', () => { - const engine = HyperFormula.buildFromArray([ - ['="abc"="abc"', '="foo"="bar"', '="a"="foo"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(false) - }) - - it('Equals operator - booleans', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()=TRUE()', '=FALSE()=FALSE()', '=TRUE()=FALSE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(false) - }) - - it('Equal operator with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo"=1', '="foo"=TRUE()', '=1="foo"', '=TRUE()="foo"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('D1'))).toBe(false) - }) - - it('Equals operator with error', () => { - const engine = HyperFormula.buildFromArray([ - ['=1/0', '=A1=2', '=2=A1'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('Not equals operator - numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=1<>2', '=1<>1', '=1+2<>3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(false) - }) - - it('Not equals operator - strings', () => { - const engine = HyperFormula.buildFromArray([ - ['="abc"<>"abc"', '="foo"<>"bar"', '="a"<>"foo"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('Not equals operator - booleans', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()<>TRUE()', '=FALSE()<>FALSE()', '=TRUE()<>FALSE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('Not equals operator with error', () => { - const engine = HyperFormula.buildFromArray([ - ['=1/0', '=A1<>2', '=2<>A1'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('Not Equal operator with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo"<>1', '="foo"<>TRUE()', '=1<>"foo"', '=TRUE()<>"foo"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(true) - }) - - it('Less than operator with number arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=1<2', '=2<2', '=-3<4', '=-4<-3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(true) - }) - - it('Less than operator with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo"<1', '="foo" { - const engine = HyperFormula.buildFromArray([ - ['="abcd"<"abc"', '="11"<"2"', '="02/02/2020"<"true"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('Less than operator with coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['=FALSE()<"2"', '="1"<"2"', '=TRUE() { - const engine = HyperFormula.buildFromArray([ - ['=2>1', '=2>2', '=4>-3', '=-3>-4'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(true) - }) - - it('Greater than operator with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo">1', '="foo">TRUE()', '=1>"0"', '=2 > TRUE()', '="02/02/2020">"000"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - }) - - it('Greater than operator with strings', () => { - const engine = HyperFormula.buildFromArray([ - ['="abcd">"abc"', '="11">"2"', '="02/02/2020">"true"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(false) - }) - - it('Greater than operator with coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['=FALSE()>"2"', '="1">"2"', '=TRUE()>FALSE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('Less than or equal operator with number arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=1<=2', '=2<=2', '=-3<=4', '=-4<=-3', '=5<=4'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(true) - expect(engine.getCellValue(adr('E1'))).toBe(false) - }) - - it('Less than or equal operator with strings', () => { - const engine = HyperFormula.buildFromArray([ - ['="abcd"<="abc"', '="11"<="2"', '="02/02/2020"<="true"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - it('Less than or equal operator with coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['=FALSE()<="2"', '="1"<="2"', '=TRUE()<=FALSE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(false) - }) - - it('Less than or equal operator with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo"<=1', '="foo"<=TRUE()', '=1<="0"', '=2 <= TRUE()', '="02/02/2020"<="000"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(true) - expect(engine.getCellValue(adr('E1'))).toBe(false) - }) - - it('Greater than or equal operator with number arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=2>=1', '=2>=2', '=4>=-3', '=-3>=-4', '=4>=5'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(true) - expect(engine.getCellValue(adr('E1'))).toBe(false) - }) - - it('Greater than or equal operator with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo">=1', '="foo">=TRUE()', '=1>="0"', '=2 >= TRUE()', '="02/02/2020">="000"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - }) - - it('Greater than or equal operator with strings', () => { - const engine = HyperFormula.buildFromArray([ - ['="abcd">="abc"', '="11">="2"', '="02/02/2020">="true"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(false) - }) - - it('Greater than or equal operator with coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['=FALSE()>="2"', '="1">="2"', '=TRUE()>=FALSE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('Less than propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)<2', '=2<(1/0)', '=(A1:B1)<(1/0)', '=(1/0)<(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - it('Greater than propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)>2', '=2>(1/0)', '=(A1:B1)>(1/0)', '=(1/0)>(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - it('Less than or equal propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)<=2', '=2<=(1/0)', '=(A1:B1)<=(1/0)', '=(1/0)<=(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - it('Greater than or equal propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)>=2', '=2>=(1/0)', '=(A1:B1)>=(1/0)', '=(1/0)>=(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - it('Equal propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)=2', '=2=(1/0)', '=(A1:B1)=(1/0)', '=(1/0)=(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - it('Not equal propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)<>2', '=2<>(1/0)', '=(A1:B1)<>(1/0)', '=(1/0)<>(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/coercions.spec.ts b/test/unit/interpreter/coercions.spec.ts deleted file mode 100644 index 6fed020c8f..0000000000 --- a/test/unit/interpreter/coercions.spec.ts +++ /dev/null @@ -1,378 +0,0 @@ -import {ErrorType, HyperFormula, SimpleRangeValue} from '../../../src' -import {CellError} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {DateTimeHelper} from '../../../src/DateTimeHelper' -import {ErrorMessage} from '../../../src/error-message' -import { - ArithmeticHelper, - coerceBooleanToNumber, - coerceScalarToBoolean, - coerceToRangeNumbersOrError, - coerceScalarToString -} from '../../../src/interpreter/ArithmeticHelper' -import {DateNumber, EmptyValue, TimeNumber} from '../../../src/interpreter/InterpreterValue' -import {NumberLiteralHelper} from '../../../src/NumberLiteralHelper' -import {adr, detailedError} from '../testUtils' - -describe('#coerceNonDateScalarToMaybeNumber', () => { - const config = new Config() - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - it('works', () => { - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber(42)).toBe(42) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber('42')).toBe(42) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber(' 42')).toBe(42) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber('42 ')).toBe(42) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber('0000042')).toBe(42) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber('42foo')).toEqual(undefined) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber('foo42')).toEqual(undefined) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber(true)).toBe(1) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber(false)).toBe(0) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber(EmptyValue)).toBe(0) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber('')).toBe(0) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber(' ')).toEqual(undefined) - expect(arithmeticHelper.coerceNonDateScalarToMaybeNumber(new CellError(ErrorType.DIV_BY_ZERO))).toEqual(undefined) - }) -}) - -describe('#coerceScalarToComplex', () => { - const config = new Config() - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - it('works', () => { - expect(arithmeticHelper.coerceScalarToComplex(42)).toEqual([42, 0]) - expect(arithmeticHelper.coerceScalarToComplex(true)).toEqual(new CellError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(arithmeticHelper.coerceScalarToComplex(EmptyValue)).toEqual([0, 0]) - expect(arithmeticHelper.coerceScalarToComplex('')).toEqual(new CellError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(arithmeticHelper.coerceScalarToComplex('1')).toEqual([1, 0]) - expect(arithmeticHelper.coerceScalarToComplex('-1.1')).toEqual([-1.1, 0]) - expect(arithmeticHelper.coerceScalarToComplex('+.1')).toEqual([0.1, 0]) - expect(arithmeticHelper.coerceScalarToComplex('1e1')).toEqual([10, 0]) - expect(arithmeticHelper.coerceScalarToComplex('1 i')).toEqual([0, 1]) - expect(arithmeticHelper.coerceScalarToComplex('-1.1j')).toEqual([0, -1.1]) - expect(arithmeticHelper.coerceScalarToComplex('+.1 i')).toEqual([0, 0.1]) - expect(arithmeticHelper.coerceScalarToComplex('1e1j')).toEqual([0, 10]) - expect(arithmeticHelper.coerceScalarToComplex('i')).toEqual([0, 1]) - expect(arithmeticHelper.coerceScalarToComplex('-i')).toEqual([0, -1]) - expect(arithmeticHelper.coerceScalarToComplex('+i')).toEqual([0, 1]) - expect(arithmeticHelper.coerceScalarToComplex('i1')).toEqual(new CellError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(arithmeticHelper.coerceScalarToComplex('--1')).toEqual(new CellError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(arithmeticHelper.coerceScalarToComplex('i+1')).toEqual(new CellError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(arithmeticHelper.coerceScalarToComplex('1+-i')).toEqual([1, -1]) - expect(arithmeticHelper.coerceScalarToComplex('0.1+.1 i')).toEqual([0.1, 0.1]) - expect(arithmeticHelper.coerceScalarToComplex(' - 1.0e+1 - - 1.0e+1j')).toEqual([-10, 10]) - expect(arithmeticHelper.coerceScalarToComplex(new CellError(ErrorType.DIV_BY_ZERO))).toEqual(new CellError(ErrorType.DIV_BY_ZERO)) - }) -}) - -describe('#coerceToRangeNumbersOrError', () => { - it('works', () => { - const simpleRangeValueOnlyNumbers = SimpleRangeValue.onlyNumbers([[1, 2]]) - const timeNumber = new TimeNumber(0, 'hh:mm:ss.ss') - expect(coerceToRangeNumbersOrError(simpleRangeValueOnlyNumbers)).toEqual(simpleRangeValueOnlyNumbers) - expect(coerceToRangeNumbersOrError(new CellError(ErrorType.DIV_BY_ZERO))).toEqual(new CellError(ErrorType.DIV_BY_ZERO)) - expect(coerceToRangeNumbersOrError(999)).toEqual(SimpleRangeValue.onlyValues([[999]])) - expect(coerceToRangeNumbersOrError(timeNumber)).toEqual(SimpleRangeValue.onlyValues([[timeNumber]])) - expect(coerceToRangeNumbersOrError('foo')).toEqual(null) - }) -}) - -describe('#coerceBooleanToNumber', () => { - it('works', () => { - expect(coerceBooleanToNumber(true)).toBe(1) - expect(coerceBooleanToNumber(false)).toBe(0) - }) - - it('behaves the same as more general coercion', () => { - const config = new Config() - const dateHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateHelper, numberLiteralsHelper) - expect(coerceBooleanToNumber(true)).toBe(arithmeticHelper.coerceScalarToNumberOrError(true) as number) - expect(coerceBooleanToNumber(false)).toBe(arithmeticHelper.coerceScalarToNumberOrError(false) as number) - }) -}) - -describe('#coerceScalarToBoolean', () => { - it('works', () => { - expect(coerceScalarToBoolean(true)).toBe(true) - expect(coerceScalarToBoolean(false)).toBe(false) - - expect(coerceScalarToBoolean(1)).toBe(true) - expect(coerceScalarToBoolean(0)).toBe(false) - expect(coerceScalarToBoolean(2)).toBe(true) - expect(coerceScalarToBoolean(-1)).toBe(true) - - expect(coerceScalarToBoolean('false')).toBe(false) - expect(coerceScalarToBoolean('FALSE')).toBe(false) - expect(coerceScalarToBoolean('true')).toBe(true) - expect(coerceScalarToBoolean('TRUE')).toBe(true) - expect(coerceScalarToBoolean(' ')).toBe(undefined) - expect(coerceScalarToBoolean(' true')).toBe(undefined) - expect(coerceScalarToBoolean('true ')).toBe(undefined) - expect(coerceScalarToBoolean('prawda')).toBe(undefined) - expect(coerceScalarToBoolean('')).toBe(false) - - expect(coerceScalarToBoolean(EmptyValue)).toBe(false) - - expect(coerceScalarToBoolean(new CellError(ErrorType.DIV_BY_ZERO))).toEqual(new CellError(ErrorType.DIV_BY_ZERO)) - }) -}) - -describe('#coerceScalarToNumberOrError', () => { - it('works', () => { - const config = new Config() - const dateHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateHelper, numberLiteralsHelper) - expect(arithmeticHelper.coerceScalarToNumberOrError(1)).toEqual(1) - - expect(arithmeticHelper.coerceScalarToNumberOrError(new CellError(ErrorType.DIV_BY_ZERO))).toEqual(new CellError(ErrorType.DIV_BY_ZERO)) - - expect(arithmeticHelper.coerceScalarToNumberOrError('31/12/1899')).toEqual(new DateNumber(1, 'DD/MM/YYYY')) - expect(arithmeticHelper.coerceScalarToNumberOrError('00:00:00')).toEqual(new TimeNumber(0, 'hh:mm:ss.sss')) - expect(arithmeticHelper.coerceScalarToNumberOrError(true)).toEqual(1) - - expect(arithmeticHelper.coerceScalarToNumberOrError('foo42')).toEqual(new CellError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - - expect(arithmeticHelper.coerceScalarToNumberOrError('1')).toEqual(1) - }) - -}) - -describe('#coerceScalarToString', () => { - it('works', () => { - expect(coerceScalarToString(true)).toBe('TRUE') - expect(coerceScalarToString(false)).toBe('FALSE') - - expect(coerceScalarToString(1)).toBe('1') - expect(coerceScalarToString(0)).toBe('0') - expect(coerceScalarToString(2)).toBe('2') - expect(coerceScalarToString(-1)).toBe('-1') - - expect(coerceScalarToString('foo')).toBe('foo') - - expect(coerceScalarToString(EmptyValue)).toBe('') - - expect(coerceScalarToString(1.42)).toBe('1.42') - - expect(coerceScalarToString(new CellError(ErrorType.DIV_BY_ZERO))).toEqual(new CellError(ErrorType.DIV_BY_ZERO)) - }) -}) - -describe('check if type coercions are applied', () => { - it('boolean to int, true vs null', () => { - const engine = HyperFormula.buildFromArray([ - [true, null, '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=+A1', '=-A1', '=A1%'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(1) //ADD - expect(engine.getCellValue(adr('D1'))).toEqual(1) //SUB - expect(engine.getCellValue(adr('E1'))).toEqual(0) //MULT - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // DIV - expect(engine.getCellValue(adr('G1'))).toEqual(1) // EXP - expect(engine.getCellValue(adr('H1'))).toEqual(true) // UNARY PLUS - expect(engine.getCellValue(adr('I1'))).toEqual(-1) // UNARY MINUS - expect(engine.getCellValue(adr('J1'))).toEqual(0.01) // PERCENTAGE - }) - - it('boolean to int, null vs true', () => { - const engine = HyperFormula.buildFromArray([ - [null, true, '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=+A1', '=-A1', '=A1%'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(1) //ADD - expect(engine.getCellValue(adr('D1'))).toEqual(-1) //SUB - expect(engine.getCellValue(adr('E1'))).toEqual(0) //MULT - expect(engine.getCellValue(adr('F1'))).toEqual(0) // DIV - expect(engine.getCellValue(adr('G1'))).toEqual(0) // EXP - expect(engine.getCellValue(adr('H1'))).toBe(null) // UNARY PLUS - expect(engine.getCellValue(adr('I1'))).toEqual(0) // UNARY MINUS - expect(engine.getCellValue(adr('J1'))).toEqual(0) // PERCENTAGE - }) - - it('boolean to int, true vs true', () => { - const engine = HyperFormula.buildFromArray([ - [true, true, '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(2) //ADD - expect(engine.getCellValue(adr('D1'))).toEqual(0) //SUB - expect(engine.getCellValue(adr('E1'))).toEqual(1) //MULT - expect(engine.getCellValue(adr('F1'))).toEqual(1) // DIV - expect(engine.getCellValue(adr('G1'))).toEqual(1) // EXP - }) - - it('boolean to int, true vs false', () => { - const engine = HyperFormula.buildFromArray([ - [true, false, '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(1) //ADD - expect(engine.getCellValue(adr('D1'))).toEqual(1) //SUB - expect(engine.getCellValue(adr('E1'))).toEqual(0) //MULT - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // DIV - expect(engine.getCellValue(adr('G1'))).toEqual(1) // EXP - }) - - it('boolean to int, false vs true', () => { - const engine = HyperFormula.buildFromArray([ - [false, true, '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(1) //ADD - expect(engine.getCellValue(adr('D1'))).toEqual(-1) //SUB - expect(engine.getCellValue(adr('E1'))).toEqual(0) //MULT - expect(engine.getCellValue(adr('F1'))).toEqual(0) // DIV - expect(engine.getCellValue(adr('G1'))).toEqual(0) // EXP - }) - - it('boolean to int, false vs false', () => { - const engine = HyperFormula.buildFromArray([ - [false, false, '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=+A1', '=-A1', '=A1%'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(0) //ADD - expect(engine.getCellValue(adr('D1'))).toEqual(0) //SUB - expect(engine.getCellValue(adr('E1'))).toEqual(0) //MULT - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // DIV - expect(engine.getCellValue(adr('G1'))).toEqual(1) // EXP - expect(engine.getCellValue(adr('H1'))).toEqual(false) // UNARY PLUS - expect(engine.getCellValue(adr('I1'))).toEqual(0) // UNARY MINUS - expect(engine.getCellValue(adr('J1'))).toEqual(0) // PERCENTAGE - }) - - it('boolean to int, null vs false', () => { - const engine = HyperFormula.buildFromArray([ - [null, false, '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(0) //ADD - expect(engine.getCellValue(adr('D1'))).toEqual(0) //SUB - expect(engine.getCellValue(adr('E1'))).toEqual(0) //MULT - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // DIV - expect(engine.getCellValue(adr('G1'))).toEqual(1) // EXP - }) - it('order operations, \'\' vs null', () => { - const engine = HyperFormula.buildFromArray([ - ['', null, '=A1>B1', '=A1=B1', '=A1<=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - expect(engine.getCellValue(adr('E1'))).toEqual(true) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - }) - it('order operations, string vs boolean', () => { - const engine = HyperFormula.buildFromArray([ - ['string', false, '=A1>B1', '=A1=B1', '=A1<=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(true) - expect(engine.getCellValue(adr('E1'))).toEqual(false) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - }) - it('order operations, null vs false', () => { - const engine = HyperFormula.buildFromArray([ - [null, false, '=A1>B1', '=A1=B1', '=A1<=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - expect(engine.getCellValue(adr('E1'))).toEqual(true) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - }) - it('order operations, null vs 1', () => { - const engine = HyperFormula.buildFromArray([ - [null, 1, '=A1>B1', '=A1=B1', '=A1<=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(true) - expect(engine.getCellValue(adr('E1'))).toEqual(false) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - }) - - it('order operations, -1 vs null', () => { - const engine = HyperFormula.buildFromArray([ - [-1, null, '=A1>B1', '=A1=B1', '=A1<=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(true) - expect(engine.getCellValue(adr('E1'))).toEqual(false) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - }) - - it('order operations, 0 vs null', () => { - const engine = HyperFormula.buildFromArray([ - [0, null, '=A1>B1', '=A1=B1', '=A1<=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - expect(engine.getCellValue(adr('E1'))).toEqual(true) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - }) - - it('order operations, 0 vs false', () => { - const engine = HyperFormula.buildFromArray([ - [0, false, '=A1>B1', '=A1=B1', '=A1<=B1', '=A1=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(true) - expect(engine.getCellValue(adr('E1'))).toEqual(false) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - expect(engine.getCellValue(adr('G1'))).toEqual(false) - }) - - it('order operations, 1 vs true', () => { - const engine = HyperFormula.buildFromArray([ - [1, true, '=A1>B1', '=A1=B1', '=A1<=B1', '=A1=B1'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(true) - expect(engine.getCellValue(adr('E1'))).toEqual(false) - expect(engine.getCellValue(adr('F1'))).toEqual(true) - expect(engine.getCellValue(adr('G1'))).toEqual(false) - }) -}) - -describe('#requiresRegex', () => { - it('config.useRegularExpressions = false && config.useWildcards = false)', () => { - const config = new Config({ useRegularExpressions: false, useWildcards: false }) - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - expect(arithmeticHelper.requiresRegex('')).toEqual(!config.matchWholeCell) - }) - - it('config.useRegularExpressions = false && config.useWildcards = true)', () => { - const config = new Config({ useRegularExpressions: false, useWildcards: true }) - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - expect(arithmeticHelper.requiresRegex('')).toEqual(false) - expect(arithmeticHelper.requiresRegex('foo')).toEqual(false) - expect(arithmeticHelper.requiresRegex('foo*bar')).toEqual(true) - expect(arithmeticHelper.requiresRegex('foo!bar')).toEqual(false) - expect(arithmeticHelper.requiresRegex('[ab][0-9]')).toEqual(false) - expect(arithmeticHelper.requiresRegex('[ab].*[0-9]')).toEqual(true) - }) - - it('config.useRegularExpressions = true && config.useWildcards = false)', () => { - const config = new Config({ useRegularExpressions: true, useWildcards: false }) - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - expect(arithmeticHelper.requiresRegex('')).toEqual(false) - expect(arithmeticHelper.requiresRegex('foo')).toEqual(false) - expect(arithmeticHelper.requiresRegex('foo*bar')).toEqual(true) - expect(arithmeticHelper.requiresRegex('foo!bar')).toEqual(true) - expect(arithmeticHelper.requiresRegex('[ab][0-9]')).toEqual(true) - expect(arithmeticHelper.requiresRegex('[ab].*[0-9]')).toEqual(true) - }) - - it('config.useRegularExpressions = true && config.useWildcards = true)', () => { - const config = new Config({ useRegularExpressions: true, useWildcards: true }) - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - expect(arithmeticHelper.requiresRegex('')).toEqual(false) - expect(arithmeticHelper.requiresRegex('foo')).toEqual(false) - expect(arithmeticHelper.requiresRegex('foo*bar')).toEqual(true) - expect(arithmeticHelper.requiresRegex('foo!bar')).toEqual(true) - expect(arithmeticHelper.requiresRegex('[ab][0-9]')).toEqual(true) - expect(arithmeticHelper.requiresRegex('[ab].*[0-9]')).toEqual(true) - }) -}) diff --git a/test/unit/interpreter/criterion-computations.spec.ts b/test/unit/interpreter/criterion-computations.spec.ts deleted file mode 100644 index bc56cbfe25..0000000000 --- a/test/unit/interpreter/criterion-computations.spec.ts +++ /dev/null @@ -1,318 +0,0 @@ -import {HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('Criterions - operators computations', () => { - it('usage of greater than operator', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A3, ">1", B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(7) - }) - - it('usage of greater than or equal operator', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A3, ">=1", B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(12) - }) - - it('usage of less than operator', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A2, "<1", B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('usage of less than or equal operator', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A3, "<=1", B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(8) - }) - - it('usage of equal operator', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A3, "=1", B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('usage of not equal operator', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A3, "<>1", B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(10) - }) - - it('empty values #1', () => { - const engine = HyperFormula.buildFromArray([ - ['1', ''], - ['2', '8'], - ['3', '9'], - ['=SUMIF(B1:B3, "=", A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('empty values #2', () => { - const engine = HyperFormula.buildFromArray([ - ['1', ''], - ['2', '8'], - ['3', '9'], - ['=SUMIF(B1:B3, "<>", A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(6) - }) - - it('empty values #3', () => { - const engine = HyperFormula.buildFromArray([ - ['1', ' '], - ['2', '1'], - ['3', 'TRUE'], - ['=SUMIF(B1:B3, "=0", A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('empty values #4', () => { - const engine = HyperFormula.buildFromArray([ - [''], - ['8'], - ['9'], - ['=COUNTIF(A1:A3, "=")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) -}) - -describe('big test', () => { - it('regex example', () => { - const formulas = [ - ['w b 2r2 x', 8.89999999999418, null, 'w', '[^hrcsx]*w ?f?', '=COUNTIF(A1:A49,E1)', '=SUMIF($A$1:$A$49,E1,$B$1:$B$49)'], - ['w F', 2.20000000001164, null, 'w b', '[^hrcsx]*w*b ?f?', '=COUNTIF(A2:A50,E2)', '=SUMIF($A$1:$A$49,E2,$B$1:$B$49)'], - ['w', 2.19999999999709, null, 'r &/or c', '[^hsx]*[cr][^hsx]*', '=COUNTIF(A3:A51,E3)', '=SUMIF($A$1:$A$49,E3,$B$1:$B$49)'], - ['w', 2.09999999999127, null, '1h', '.*1h[^sx]*', '=COUNTIF(A4:A52,E4)', '=SUMIF($A$1:$A$49,E4,$B$1:$B$49)'], - ['w b 1c2 x', 2.40000000000873, null, '2h', '.*2h[^sx]*', '=COUNTIF(A5:A53,E5)', '=SUMIF($A$1:$A$49,E5,$B$1:$B$49)'], - ['w 1c1 F', 4.39999999999418, null, '1h 1s', '.*1h.*1s.*[^x]', '=COUNTIF(A9:A57,E6)', '=SUMIF($A$1:$A$49,E6,$B$1:$B$49)'], - ['w b F', 2.30000000000291, null, '2h 1s', '.*2h.*1s.*[^x]', '=COUNTIF(A11:A59,E7)', '=SUMIF($A$1:$A$49,E7,$B$1:$B$49)'], - ['w F', 2.30000000000291, null, '3h 1s', '.*3h.*1s.*[^x]', '=COUNTIF(A12:A60,E8)', '=SUMIF($A$1:$A$49,E8,$B$1:$B$49)'], - ['w F', 2.09999999999127, null, '2h 2s', '.*2h.*2s.*[^x]', '=COUNTIF(A15:A63,E9)', '=SUMIF($A$1:$A$49,E9,$B$1:$B$49)'], - ['w F b', 2.20000000001164, null, '3h 2s', '.*3h.*2s.*[^x]', '=COUNTIF(A16:A64,E10)', '=SUMIF($A$1:$A$49,E10,$B$1:$B$49)'], - ['w', 2.29999999998836, null, '4h 2s', '.*4h.*2s.*[^x]', '=COUNTIF(A19:A67,E11)', '=SUMIF($A$1:$A$49,E11,$B$1:$B$49)'], - ['w 2r2', 3.30000000000291, null, '5h 2s', '.*5h.*2s.*[^x]', '=COUNTIF(A20:A68,E12)', '=SUMIF($A$1:$A$49,E12,$B$1:$B$49)'], - ['w 1r3', 2.30000000000291, null, '4h 3s', '.*4h.*3s.*[^x]', '=COUNTIF(A22:A70,E13)', '=SUMIF($A$1:$A$49,E13,$B$1:$B$49)'], - ['wF', 3.39999999999418, null, '5h 3s', '.*5h.*3s.*[^x]', '=COUNTIF(A23:A71,E14)', '=SUMIF($A$1:$A$49,E14,$B$1:$B$49)'], - ['wF', 3.20000000001164, null, '5h 4s', '.*5h.*4s.*[^x]', '=COUNTIF(A24:A72,E15)', '=SUMIF($A$1:$A$49,E15,$B$1:$B$49)'], - ['wF', 3.29999999998836, null, '6h 4s', '.*6h.*4s.*[^x]', '=COUNTIF(A26:A74,E16)', '=SUMIF($A$1:$A$49,E16,$B$1:$B$49)'], - ['wF', 3.30000000000291, null, '7h 4s', '.*7h.*4s.*[^x]', '=COUNTIF(A28:A76,E17)', '=SUMIF($A$1:$A$49,E17,$B$1:$B$49)'], - ['wF', 3.30000000000291, null, '7h 5s', '.*7h.*5s.*[^x]', '=COUNTIF(A29:A77,E18)', '=SUMIF($A$1:$A$49,E18,$B$1:$B$49)'], - ['w F 2r3', 5.60000000000582, null, '9h 9s', '.*9h.*9s.*[^x]', '=COUNTIF(A30:A78,E19)', '=SUMIF($A$1:$A$49,E19,$B$1:$B$49)'], - ['w 2r1', 3.29999999998836, null, 'x', '.*x.*', '=COUNTIF(A1:A49,E20)', '=SUMIF($A$1:$A$49,E20,$B$1:$B$49)'], - ['w F 2r1', 4.5], - ['w 1r2', 3.30000000000291], - ['w b 2r1 1c1', 5.60000000000582], - ['w 1r1 1c1', 3.30000000000291], - ['w F', 2.29999999998836], - ['F w', 2.20000000001164], - ['Fw', 2.19999999999709], - ['w 2r2 1c1', 5.59999999999127], - ['w 1c2', 2.20000000001164], - ['w 2r2 1h1 F x', 6.59999999999127], - ['w 2r2 1h1 x', 6.69999999999709], - ['w 2h1 F', 5.60000000000582], - ['w 2h1', 6.60000000000582], - ['F w 2h1', 5.59999999999127], - ['w 2h1', 6.69999999999709], - ['w 2h1', 6.60000000000582], - ['w 2h1 1s1', 13.3999999999942], - ['w 2h1 1s1', 11.1000000000058], - ['w 2h1 1s1 F', 11.1000000000058], - ['w 2h1 1s1 F b', 12.1999999999971], - ['w 2h1 1s1', 11.0999999999913], - ['w 2h1 1s1 F b', 12.2000000000116], - ['w 2h1 1s1 F', 11.0999999999913], - ['w 3h1 1s1 F', 11.1999999999971], - ['w 3h1 1s1 F', 12.2000000000116], - ['w 3h1 1s1 F 1r1', 12.1999999999971], - ['w 3h1 1s1 Fx', 24.5], - ['w 3h1 1s1 F', 10], - ['w 3h1 1s1 F', 12.1999999999971], - [], - ['=COUNTA(A1:A49)', '=SUM(B1:B50)', null, null, 'codes counted > ', '=SUM(F1:F20)', '=SUM(G1:G21)'], - ] - - const engine = HyperFormula.buildFromArray(formulas, {useRegularExpressions: true, precisionRounding: 13}) - - expect(engine.getCellValue(adr('B51'))).toEqual(304.5) - expect(engine.getCellValue(adr('G51'))).toEqual(304.5) - - expect(engine.getCellValue(adr('F1'))).toEqual(14) - expect(engine.getCellValue(adr('F2'))).toEqual(2) - expect(engine.getCellValue(adr('F3'))).toEqual(11) - expect(engine.getCellValue(adr('F4'))).toEqual(0) - expect(engine.getCellValue(adr('F5'))).toEqual(5) - expect(engine.getCellValue(adr('F6'))).toEqual(0) - expect(engine.getCellValue(adr('F7'))).toEqual(7) - expect(engine.getCellValue(adr('F8'))).toEqual(5) - expect(engine.getCellValue(adr('F9'))).toEqual(0) - expect(engine.getCellValue(adr('F10'))).toEqual(0) - expect(engine.getCellValue(adr('F11'))).toEqual(0) - expect(engine.getCellValue(adr('F12'))).toEqual(0) - expect(engine.getCellValue(adr('F13'))).toEqual(0) - expect(engine.getCellValue(adr('F14'))).toEqual(0) - expect(engine.getCellValue(adr('F15'))).toEqual(0) - expect(engine.getCellValue(adr('F16'))).toEqual(0) - expect(engine.getCellValue(adr('F17'))).toEqual(0) - expect(engine.getCellValue(adr('F18'))).toEqual(0) - expect(engine.getCellValue(adr('F19'))).toEqual(0) - expect(engine.getCellValue(adr('F20'))).toEqual(5) - - expect(engine.getCellValue(adr('G1'))).toEqual(36.39999999998) - expect(engine.getCellValue(adr('G2'))).toEqual(4.5000000000146) - expect(engine.getCellValue(adr('G3'))).toEqual(43.400000000009) - expect(engine.getCellValue(adr('G4'))).toEqual(0) - expect(engine.getCellValue(adr('G5'))).toEqual(31.100000000006) - expect(engine.getCellValue(adr('G6'))).toEqual(0) - expect(engine.getCellValue(adr('G7'))).toEqual(82.199999999997) - expect(engine.getCellValue(adr('G8'))).toEqual(57.800000000003) - expect(engine.getCellValue(adr('G9'))).toEqual(0) - expect(engine.getCellValue(adr('G10'))).toEqual(0) - expect(engine.getCellValue(adr('G11'))).toEqual(0) - expect(engine.getCellValue(adr('G12'))).toEqual(0) - expect(engine.getCellValue(adr('G13'))).toEqual(0) - expect(engine.getCellValue(adr('G14'))).toEqual(0) - expect(engine.getCellValue(adr('G15'))).toEqual(0) - expect(engine.getCellValue(adr('G16'))).toEqual(0) - expect(engine.getCellValue(adr('G17'))).toEqual(0) - expect(engine.getCellValue(adr('G18'))).toEqual(0) - expect(engine.getCellValue(adr('G19'))).toEqual(0) - expect(engine.getCellValue(adr('G20'))).toEqual(49.099999999991) - }) - - it('Gnumeric test file', () => { - const formulas = [ - [null, null, '=IF(AND(C10:C49), "All ok", "Bug!")'], - [], - [], - [], - [], - ['1', null, null, null, '1', null, null, 'TRUE', null, null, 'TRUE', '\'1', 'Jesper'], - ['2', '8', null, null, '2', '1', null, 'FALSE', '8', null, '\'TRUE', '1', 'apples'], - ['3', '9', null, null, '3', 'TRUE', null, '\'1.0', '9', null, null, '\'1.0', ], - [], - ['=SUMIF($B$6:$B$8, "=", $A$6:$A$8)', '1', '=A10=B10'], - ['=SUMIF($B$6:$B$8, ">=", $A$6:$A$8)', '0', '=A11=B11'], - ['=SUMIF($B$6:$B$8, "<=", $A$6:$A$8)', '0', '=A12=B12'], - ['=SUMIF($B$6:$B$8, "<>", $A$6:$A$8)', '5', '=A13=B13'], - ['=SUMIF($B$6:$B$8, "<>x", $A$6:$A$8)', '6', '=A14=B14'], - ['=SUMIF($B$6:$B$8, ">", $A$6:$A$8)', '0', '=A15=B15'], - ['=SUMIF($B$6:$B$8, "<", $A$6:$A$8)', '0', '=A16=B16'], - ['=SUMIF($B$6:$B$8, "=8.0", $A$6:$A$8)', '2', '=A17=B17'], - ['=SUMIF($B$6:$B$8, "= 8.0", $A$6:$A$8)', '2', '=A18=B18'], - ['=SUMIF($B$6:$B$8, "= 8.0 ", $A$6:$A$8)', '2', '=A19=B19'], - ['=SUMIF($B$6:$B$8, "= 8.0 ", $A$6:$A$8)', '2', '=A20=B20'], - ['=SUMIF($F$6:$F$8, "=TRUE", $E$6:$E$8)', '3', '=A21=B21'], - ['=SUMIF($F$6:$F$8, "=1", $E$6:$E$8)', '2', '=A22=B22'], - ['=SUMIF($F$6:$F$8, "=0", $E$6:$E$8)', '0', '=A23=B23'], - ['=SUMIF($F$6:$F$8, "=FALSE", $E$6:$E$8)', '0', '=A24=B24'], - ['=SUMIF($F$6:$F$8, "=T", $E$6:$E$8)', '0', '=A25=B25'], - ['=SUMIF($F$6:$F$8, "=1.0", $E$6:$E$8)', '2', '=A26=B26'], - ['=SUMIF($F$6:$F$8, "=x", $E$6:$E$8)', '0', '=A27=B27'], - ['=SUMIF($I$6:$I$8, "=", $H$6:$H$8)', '0', '=A28=B28'], - ['=SUMIF($I$6:$I$8, "=9", $H$6:$H$8)', '0', '=A29=B29'], - ['=SUMIF($I$6:$I$8, "=1.0", $H$6:$H$8)', '0', '=A30=B30'], - ['=COUNTIF($I$6:$I$8, "=")', '1', '=A31=B31'], - ['=COUNTIF($H$6:$H$8, "1")', '1', '=A32=B32'], - ['=SUMIF($H$6:$H$8, "=TRUE")', '0', '=A33=B33'], - ['=COUNTIF($K$6:$K$6, "TRUE")', '1', '=A34=B34'], - ['=COUNTIF($K$6:$K$6, TRUE)', '1', '=A35=B35'], - ['=COUNTIF($K$7:$K$7, "TRUE")', '0', '=A36=B36'], - ['=COUNTIF($K$7:$K$7, TRUE)', '0', '=A37=B37'], - ['=COUNTIF($K$6:$K$8, "TRUE")', '1', '=A38=B38'], - ['=COUNTIF($K$6:$K$8, "=TRUE")', '1', '=A39=B39'], - ['=COUNTIF($K$6:$K$8, "~TRUE")', '0', '=A40=B40'], - ['=COUNTIF($K$6:$K$8, TRUE)', '1', '=A41=B41'], - ['=COUNTIF($L$6:$L$8, "1")', '3', '=A42=B42'], - ['=COUNTIF($L$6:$L$8, "1.0")', '3', '=A43=B43'], - ['=COUNTIF($L$6:$L$8, 1)', '3', '=A44=B44'], - ['=COUNTIF($M$6:$M$7, "es")', '0', '=A45=B45'], - ['=COUNTIF($M$6:$M$7, "*es")', '1', '=A46=B46'], - ['=COUNTIF($M$6:$M$7, "es*")', '0', '=A47=B47'], - ['=COUNTIF($M$6:$M$7, "*es*")', '2', '=A48=B48'], - ['=COUNTIF($M$6:$M$7, "*ES*")', '2', '=A49=B49'] - ] - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('TRUE', '=TRUE()', undefined) - engine.addNamedExpression('FALSE', '=FALSE()', undefined) - engine.setCellContents(adr('A1'), formulas) - expect(engine.getCellValue(adr('A10'))).toEqual(1) - expect(engine.getCellValue(adr('A11'))).toEqual(0) - expect(engine.getCellValue(adr('A12'))).toEqual(0) - expect(engine.getCellValue(adr('A13'))).toEqual(5) - expect(engine.getCellValue(adr('A14'))).toEqual(6) - expect(engine.getCellValue(adr('A15'))).toEqual(0) - expect(engine.getCellValue(adr('A16'))).toEqual(0) - expect(engine.getCellValue(adr('A17'))).toEqual(2) - expect(engine.getCellValue(adr('A18'))).toEqual(2) - expect(engine.getCellValue(adr('A19'))).toEqual(2) - expect(engine.getCellValue(adr('A20'))).toEqual(2) - expect(engine.getCellValue(adr('A21'))).toEqual(3) - expect(engine.getCellValue(adr('A22'))).toEqual(2) - expect(engine.getCellValue(adr('A23'))).toEqual(0) - expect(engine.getCellValue(adr('A24'))).toEqual(0) - expect(engine.getCellValue(adr('A25'))).toEqual(0) - expect(engine.getCellValue(adr('A26'))).toEqual(2) - expect(engine.getCellValue(adr('A27'))).toEqual(0) - expect(engine.getCellValue(adr('A28'))).toEqual(0) - expect(engine.getCellValue(adr('A29'))).toEqual(0) - expect(engine.getCellValue(adr('A30'))).toEqual(0) - expect(engine.getCellValue(adr('A31'))).toEqual(1) - expect(engine.getCellValue(adr('A32'))).toEqual(1) - expect(engine.getCellValue(adr('A33'))).toEqual(0) - expect(engine.getCellValue(adr('A34'))).toEqual(1) - // expect(engine.getCellValue(adr('A35'))).toEqual(1) - expect(engine.getCellValue(adr('A36'))).toEqual(0) - // expect(engine.getCellValue(adr('A37'))).toEqual(0) - expect(engine.getCellValue(adr('A38'))).toEqual(1) - expect(engine.getCellValue(adr('A39'))).toEqual(1) - // expect(engine.getCellValue(adr('A40'))).toEqual(0) - // expect(engine.getCellValue(adr('A41'))).toEqual(1) - expect(engine.getCellValue(adr('A42'))).toEqual(3) - expect(engine.getCellValue(adr('A43'))).toEqual(3) - // expect(engine.getCellValue(adr('A44'))).toEqual(3) - expect(engine.getCellValue(adr('A45'))).toEqual(0) - expect(engine.getCellValue(adr('A46'))).toEqual(1) - expect(engine.getCellValue(adr('A47'))).toEqual(0) - expect(engine.getCellValue(adr('A48'))).toEqual(2) - expect(engine.getCellValue(adr('A49'))).toEqual(2) - // expect(engine.getCellValue(adr('C1'))).toEqual('All ok') - }) -}) diff --git a/test/unit/interpreter/cyclical-deps.spec.ts b/test/unit/interpreter/cyclical-deps.spec.ts deleted file mode 100644 index e6555e1d83..0000000000 --- a/test/unit/interpreter/cyclical-deps.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {adr, detailedError} from '../testUtils' - -describe('Cyclical dependencies and error literals', () => { - it('Cyclical errors might not propagate', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2', '=A1'], - ['=ISERROR(A1)', '=ISERROR(B1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B2'))).toEqual(true) - }) - it('Errors should be parsed and propagated', () => { - const engine = HyperFormula.buildFromArray([ - ['=B1', '=A1', '=ISERROR(B1)', '=C1+D1', '=ISERROR(D1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('E1'))).toEqual(true) - }) -}) diff --git a/test/unit/interpreter/date-and-time-arithmetic.spec.ts b/test/unit/interpreter/date-and-time-arithmetic.spec.ts deleted file mode 100644 index eede5f2e6d..0000000000 --- a/test/unit/interpreter/date-and-time-arithmetic.spec.ts +++ /dev/null @@ -1,311 +0,0 @@ -import {CellValueDetailedType, HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('Date arithmetic', () => { - it('subtract two dates', () => { - const engine = HyperFormula.buildFromArray([ - ['02/02/2020', '06/02/2019', '=A1-B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(361) - }) - - it('subtract two dates with custom date format', () => { - const engine = HyperFormula.buildFromArray([ - ['09/20/2022', '09/25/2022', '=B1-A1'], - ], { dateFormats: ['MM/DD/YYYY'] }) - - expect(engine.getCellValue(adr('C1'))).toBe(5) - }) - - it('compare two dates', () => { - const engine = HyperFormula.buildFromArray([ - ['02/02/2020', '02/06/2019', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - }) - - it('compare two datestrings', () => { - const engine = HyperFormula.buildFromArray([ - ['="02/02/2020"', '="02/06/2019"', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - }) - - it('compare date with datestring, different dates', () => { - const engine = HyperFormula.buildFromArray([ - ['="02/02/2020"', '02/06/2019', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1=B1', '=A1<>B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - expect(engine.getCellValue(adr('G1'))).toBe(false) - expect(engine.getCellValue(adr('H1'))).toBe(true) - }) - - it('compare date with datestring, the same dates', () => { - const engine = HyperFormula.buildFromArray([ - ['="02/02/2020"', '02/02/2020', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1=B1', '=A1<>B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(true) - expect(engine.getCellValue(adr('G1'))).toBe(true) - expect(engine.getCellValue(adr('H1'))).toBe(false) - }) - - it('compare date with bool', () => { - const engine = HyperFormula.buildFromArray([ - ['="02/02/2020"', '=TRUE()', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('D1'))).toBe(true) - expect(engine.getCellValue(adr('E1'))).toBe(false) - expect(engine.getCellValue(adr('F1'))).toBe(true) - }) - - it('compare date with number', () => { - const engine = HyperFormula.buildFromArray([ - ['02/02/2020', '2', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - }) - - it('sum date with number', () => { - const engine = HyperFormula.buildFromArray([ - ['02/02/2020', '2', '=A1+B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(43865) - }) - - it('sum date with boolean', () => { - const engine = HyperFormula.buildFromArray([ - ['02/02/2020', '=TRUE()', '=A1+B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(43864) - }) - - it('functions on dates', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISEVEN("02/02/2020")', '=COS("02/02/2020")', '=BITOR("02/02/2020","16/08/1985")'], - ], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(0.9965266857693633) - expect(engine.getCellValue(adr('C1'))).toBe(64383) - }) -}) - -describe('Time arithmetic', () => { - it('subtract two time values', () => { - const engine = HyperFormula.buildFromArray([ - ['13:13', '11:50', '=TEXT(A1-B1, "hh:mm")'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe('01:23') - }) - - it('subtract two time values - rounding test', () => { - const engine = HyperFormula.buildFromArray([ - ['15:00', '14:00', '=TEXT(A1-B1, "hh:mm")'], - ['15:01', '14:00', '=TEXT(A2-B2, "hh:mm")'], - ['15:02', '14:00', '=TEXT(A3-B3, "hh:mm")'], - ['15:03', '14:00', '=TEXT(A4-B4, "hh:mm")'], - ['15:04', '14:00', '=TEXT(A5-B5, "hh:mm")'], - ['15:05', '14:00', '=TEXT(A6-B6, "hh:mm")'], - ['15:06', '14:00', '=TEXT(A7-B7, "hh:mm")'], - ['15:07', '14:00', '=TEXT(A8-B8, "hh:mm")'], - ['15:08', '14:00', '=TEXT(A9-B9, "hh:mm")'], - ['15:09', '14:00', '=TEXT(A10-B10, "hh:mm")'], - ['15:10', '14:00', '=TEXT(A11-B11, "hh:mm")'], - ['15:11', '14:00', '=TEXT(A12-B12, "hh:mm")'], - ['15:12', '14:00', '=TEXT(A13-B13, "hh:mm")'], - ['15:13', '14:00', '=TEXT(A14-B14, "hh:mm")'], - ['15:14', '14:00', '=TEXT(A15-B15, "hh:mm")'], - ['15:15', '14:00', '=TEXT(A16-B16, "hh:mm")'], - ['15:16', '14:00', '=TEXT(A17-B17, "hh:mm")'], - ['15:17', '14:00', '=TEXT(A18-B18, "hh:mm")'], - ['15:18', '14:00', '=TEXT(A19-B19, "hh:mm")'], - ['15:19', '14:00', '=TEXT(A20-B20, "hh:mm")'], - ['15:20', '14:00', '=TEXT(A21-B21, "hh:mm")'], - ['15:21', '14:00', '=TEXT(A22-B22, "hh:mm")'], - ['15:22', '14:00', '=TEXT(A23-B23, "hh:mm")'], - ['15:23', '14:00', '=TEXT(A24-B24, "hh:mm")'], - ['15:24', '14:00', '=TEXT(A25-B25, "hh:mm")'], - ['15:25', '14:00', '=TEXT(A26-B26, "hh:mm")'], - ['15:26', '14:00', '=TEXT(A27-B27, "hh:mm")'], - ['15:27', '14:00', '=TEXT(A28-B28, "hh:mm")'], - ['15:28', '14:00', '=TEXT(A29-B29, "hh:mm")'], - ['15:29', '14:00', '=TEXT(A30-B30, "hh:mm")'], - ['15:30', '14:00', '=TEXT(A31-B31, "hh:mm")'], - ['15:31', '14:00', '=TEXT(A32-B32, "hh:mm")'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe('01:00') - expect(engine.getCellValue(adr('C2'))).toBe('01:01') - expect(engine.getCellValue(adr('C3'))).toBe('01:02') - expect(engine.getCellValue(adr('C4'))).toBe('01:03') - expect(engine.getCellValue(adr('C5'))).toBe('01:04') - expect(engine.getCellValue(adr('C6'))).toBe('01:05') - expect(engine.getCellValue(adr('C7'))).toBe('01:06') - expect(engine.getCellValue(adr('C8'))).toBe('01:07') - expect(engine.getCellValue(adr('C9'))).toBe('01:08') - expect(engine.getCellValue(adr('C10'))).toBe('01:09') - expect(engine.getCellValue(adr('C11'))).toBe('01:10') - expect(engine.getCellValue(adr('C12'))).toBe('01:11') - expect(engine.getCellValue(adr('C13'))).toBe('01:12') - expect(engine.getCellValue(adr('C14'))).toBe('01:13') - expect(engine.getCellValue(adr('C15'))).toBe('01:14') - expect(engine.getCellValue(adr('C16'))).toBe('01:15') - expect(engine.getCellValue(adr('C17'))).toBe('01:16') - expect(engine.getCellValue(adr('C18'))).toBe('01:17') - expect(engine.getCellValue(adr('C19'))).toBe('01:18') - expect(engine.getCellValue(adr('C20'))).toBe('01:19') - expect(engine.getCellValue(adr('C21'))).toBe('01:20') - expect(engine.getCellValue(adr('C22'))).toBe('01:21') - expect(engine.getCellValue(adr('C23'))).toBe('01:22') - expect(engine.getCellValue(adr('C24'))).toBe('01:23') - expect(engine.getCellValue(adr('C25'))).toBe('01:24') - expect(engine.getCellValue(adr('C26'))).toBe('01:25') - expect(engine.getCellValue(adr('C27'))).toBe('01:26') - expect(engine.getCellValue(adr('C28'))).toBe('01:27') - expect(engine.getCellValue(adr('C29'))).toBe('01:28') - expect(engine.getCellValue(adr('C30'))).toBe('01:29') - expect(engine.getCellValue(adr('C31'))).toBe('01:30') - expect(engine.getCellValue(adr('C32'))).toBe('01:31') - }) - - it('compare two time values', () => { - const engine = HyperFormula.buildFromArray([ - ['13:13', '11:50', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - }) - - it('compare two time-strings', () => { - const engine = HyperFormula.buildFromArray([ - ['="13:13"', '="11:50"', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - }) - - it('compare a time value with a time-string, non-equal', () => { - const engine = HyperFormula.buildFromArray([ - ['="13:13"', '11:50', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1=B1', '=A1<>B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - expect(engine.getCellValue(adr('G1'))).toBe(false) - expect(engine.getCellValue(adr('H1'))).toBe(true) - }) - - it('compare a time value with a time-string, equal', () => { - const engine = HyperFormula.buildFromArray([ - ['="13:13"', '13:13', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1=B1', '=A1<>B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(true) - expect(engine.getCellValue(adr('G1'))).toBe(true) - expect(engine.getCellValue(adr('H1'))).toBe(false) - }) - - it('compare a time-string with a boolean value', () => { - const engine = HyperFormula.buildFromArray([ - ['="13:13"', '=TRUE()', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('D1'))).toBe(true) - expect(engine.getCellValue(adr('E1'))).toBe(false) - expect(engine.getCellValue(adr('F1'))).toBe(true) - }) - - it('compare a time value with a number', () => { - const engine = HyperFormula.buildFromArray([ - ['13:13', '0.01', '=A1>B1', '=A1=B1', '=A1<=B1'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toBe(false) - expect(engine.getCellValue(adr('E1'))).toBe(true) - expect(engine.getCellValue(adr('F1'))).toBe(false) - }) - - it('sum a time value with a number', () => { - const engine = HyperFormula.buildFromArray([ - ['13:13', '2', '=A1+B1', '=TEXT(A1+B1, "hh:mm")'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBeGreaterThan(2) - expect(engine.getCellValue(adr('D1'))).toBe('13:13') - }) - - it('sum a time value with boolean', () => { - const engine = HyperFormula.buildFromArray([ - ['13:13', '=TRUE()', '=A1+B1', '=TEXT(A1+B1, "hh:mm")'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBeGreaterThan(1) - expect(engine.getCellValue(adr('D1'))).toBe('13:13') - }) - - it('apply a numeric function to a time value', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISODD("13:13")', '=COS("13:13")'], - ], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(0.8521613392800845) - }) - - it('Don\'t convert string to time value when prepended with apostrophe', () => { - const engine = HyperFormula.buildFromArray([ - ["'13:13"], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('13:13') - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.STRING) - }) - - it('Don\'t convert string to time value when there is no timeFormats configured', () => { - const engine = HyperFormula.buildFromArray([ - ['1:80'], - ], { timeFormats: [] }) - - expect(engine.getCellValue(adr('A1'))).toEqual('1:80') - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.STRING) - }) -}) diff --git a/test/unit/interpreter/error-literals.spec.ts b/test/unit/interpreter/error-literals.spec.ts deleted file mode 100644 index 67f0357032..0000000000 --- a/test/unit/interpreter/error-literals.spec.ts +++ /dev/null @@ -1,92 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Error literals', () => { - it('Errors should be parsed and propagated', () => { - const engine = HyperFormula.buildFromArray([ - ['#DIV/0!', '=A1', '=#DIV/0!'], - ['=ISERROR(A1)', '=ISERROR(B1)', '=ISERROR(C1)', '=ISERROR(#DIV/0!)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqual(true) - expect(engine.getCellValue(adr('B2'))).toEqual(true) - expect(engine.getCellValue(adr('C2'))).toEqual(true) - }) - - it('should return error when unknown error literal in formula', () => { - const engine = HyperFormula.buildFromArray([ - ['#UNKNOWN!', '=#UNKNOWN!'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('#UNKNOWN!') - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('error #N/A! with every combination should be supported by all comparison operators', () => { - const engine = HyperFormula.buildFromArray([ - ['#N/A', 0, '=A1=B1', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1<>B1', '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=A1&B1', '=+A1', '=-A1', '=A1%'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA)) // EQUAL - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA)) // GT - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.NA)) // LT - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.NA)) // GTE - expect(engine.getCellValue(adr('G1'))).toEqualError(detailedError(ErrorType.NA)) // LTE - expect(engine.getCellValue(adr('H1'))).toEqualError(detailedError(ErrorType.NA)) // NOT EQUAL - expect(engine.getCellValue(adr('I1'))).toEqualError(detailedError(ErrorType.NA)) // ADD - expect(engine.getCellValue(adr('J1'))).toEqualError(detailedError(ErrorType.NA)) // SUB - expect(engine.getCellValue(adr('K1'))).toEqualError(detailedError(ErrorType.NA)) // MULT - expect(engine.getCellValue(adr('L1'))).toEqualError(detailedError(ErrorType.NA)) // DIV - expect(engine.getCellValue(adr('M1'))).toEqualError(detailedError(ErrorType.NA)) // EXP - expect(engine.getCellValue(adr('N1'))).toEqualError(detailedError(ErrorType.NA)) // CONCAT - expect(engine.getCellValue(adr('O1'))).toEqualError(detailedError(ErrorType.NA)) // UNARY PLUS - expect(engine.getCellValue(adr('P1'))).toEqualError(detailedError(ErrorType.NA)) // UNARY MINUS - expect(engine.getCellValue(adr('Q1'))).toEqualError(detailedError(ErrorType.NA)) // PERCENTAGE - }) - - it('error #DIV/0! with every combination should be supported by all comparison operators', () => { - const engine = HyperFormula.buildFromArray([ - ['#DIV/0!', null, '=A1=B1', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1<>B1', '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=A1&B1', '=+A1', '=-A1', '=A1%'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // EQUAL - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // GT - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // LT - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // GTE - expect(engine.getCellValue(adr('G1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // LTE - expect(engine.getCellValue(adr('H1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // NOT EQUAL - expect(engine.getCellValue(adr('I1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) //ADD - expect(engine.getCellValue(adr('J1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) //SUB - expect(engine.getCellValue(adr('K1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) //MULT - expect(engine.getCellValue(adr('L1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // DIV - expect(engine.getCellValue(adr('M1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // EXP - expect(engine.getCellValue(adr('N1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // CONCAT - expect(engine.getCellValue(adr('O1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // UNARY PLUS - expect(engine.getCellValue(adr('P1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // UNARY MINUS - expect(engine.getCellValue(adr('Q1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // PERCENTAGE - }) - - it('error #CYCLE! with every combination should be supported by all comparison operators', () => { - const engine = HyperFormula.buildFromArray([ - ['#CYCLE!', null, '=A1=B1', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1<>B1', '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=A1&B1', '=+A1', '=-A1', '=A1%'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.CYCLE)) // EQUAL - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.CYCLE)) // GT - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.CYCLE)) // LT - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.CYCLE)) // GTE - expect(engine.getCellValue(adr('G1'))).toEqualError(detailedError(ErrorType.CYCLE)) // LTE - expect(engine.getCellValue(adr('H1'))).toEqualError(detailedError(ErrorType.CYCLE)) // NOT EQUAL - expect(engine.getCellValue(adr('I1'))).toEqualError(detailedError(ErrorType.CYCLE)) //ADD - expect(engine.getCellValue(adr('J1'))).toEqualError(detailedError(ErrorType.CYCLE)) //SUB - expect(engine.getCellValue(adr('K1'))).toEqualError(detailedError(ErrorType.CYCLE)) //MULT - expect(engine.getCellValue(adr('L1'))).toEqualError(detailedError(ErrorType.CYCLE)) // DIV - expect(engine.getCellValue(adr('M1'))).toEqualError(detailedError(ErrorType.CYCLE)) // EXP - expect(engine.getCellValue(adr('N1'))).toEqualError(detailedError(ErrorType.CYCLE)) // CONCAT - expect(engine.getCellValue(adr('O1'))).toEqualError(detailedError(ErrorType.CYCLE)) // UNARY PLUS - expect(engine.getCellValue(adr('P1'))).toEqualError(detailedError(ErrorType.CYCLE)) // UNARY MINUS - expect(engine.getCellValue(adr('Q1'))).toEqualError(detailedError(ErrorType.CYCLE)) // PERCENTAGE - }) -}) diff --git a/test/unit/interpreter/function-abs.spec.ts b/test/unit/interpreter/function-abs.spec.ts deleted file mode 100644 index fb7bf96eb4..0000000000 --- a/test/unit/interpreter/function-abs.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ABS', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([ - ['=ABS(-1)', '=ABS(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - }) - - it('given wrong argument type', () => { - const engine = HyperFormula.buildFromArray([ - ['=ABS("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="2"', '=ABS(A1)'], - ['=TRUE()', '=ABS(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('B2'))).toEqual(1) - }) - - it('given wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ABS()'], - ['=ABS(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ABS(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-acos.spec.ts b/test/unit/interpreter/function-acos.spec.ts deleted file mode 100644 index 18daa1f1ea..0000000000 --- a/test/unit/interpreter/function-acos.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ACOS', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ACOS(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.0471975511966) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ACOS("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('for 1 (edge)', () => { - const engine = HyperFormula.buildFromArray([['=ACOS(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - }) - - it('for -1 (edge)', () => { - const engine = HyperFormula.buildFromArray([['=ACOS(-1)']], - {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(Math.PI) - }) - - it('when value too large', () => { - const engine = HyperFormula.buildFromArray([['=ACOS(1.1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('when value too small', () => { - const engine = HyperFormula.buildFromArray([['=ACOS(-1.1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ACOS()', '=ACOS(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=ACOS(A1)'], - ['=TRUE()', '=ACOS(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(3.141592654) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(0) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ACOS(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-acosh.spec.ts b/test/unit/interpreter/function-acosh.spec.ts deleted file mode 100644 index e3de7d15bf..0000000000 --- a/test/unit/interpreter/function-acosh.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ACOSH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ACOSH(1)', '=ACOSH(2)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.31695789692482) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ACOSH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('too small', () => { - const engine = HyperFormula.buildFromArray([['=ACOSH(0.9)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ACOSH()', '=ACOSH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="1"', '=ACOSH(A1)'], - ['=TRUE()', '=ACOSH(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('B2'))).toEqual(0) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ACOSH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-acot.spec.ts b/test/unit/interpreter/function-acot.spec.ts deleted file mode 100644 index 3c7a000ce7..0000000000 --- a/test/unit/interpreter/function-acot.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ACOT', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ACOT(0)', '=ACOT(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.5707963267949) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.785398163397448) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ACOT("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ACOT()', '=ACOT(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=ACOT(A1)'], - ['', '=ACOT(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.785398163397448) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(1.5707963267949, 10) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ACOT(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-acoth.spec.ts b/test/unit/interpreter/function-acoth.spec.ts deleted file mode 100644 index 1145bfd318..0000000000 --- a/test/unit/interpreter/function-acoth.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ACOTH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ACOTH(2)']], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5493061443340548) - }) - - it('error for 1', () => { - const engine = HyperFormula.buildFromArray([['=ACOTH(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('error for -1', () => { - const engine = HyperFormula.buildFromArray([['=ACOTH(-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ACOTH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ACOTH()', '=ACOTH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="2"', '=ACOTH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.5493061443340548) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ACOTH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-address.spec.ts b/test/unit/interpreter/function-address.spec.ts deleted file mode 100644 index 3391ba5c62..0000000000 --- a/test/unit/interpreter/function-address.spec.ts +++ /dev/null @@ -1,299 +0,0 @@ -import {HyperFormula, ErrorType} from '../../../src' -import {adr, detailedError} from '../testUtils' -import {ErrorMessage} from '../../../src/error-message' - -describe('ADDRESS', () => { - it('with row and col', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1,1)'], - ['=ADDRESS(77,300)'], - ['=ADDRESS(ROW(),300)'], - ['=ADDRESS(45,COLUMN())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('$A$1') - expect(engine.getCellValue(adr('A2'))).toEqual('$KN$77') - expect(engine.getCellValue(adr('A3'))).toEqual('$KN$3') - expect(engine.getCellValue(adr('A4'))).toEqual('$A$45') - }) - - it('with row, col, and abs (A1 Notation)', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1,1,1)'], - ['=ADDRESS(1,1,2)'], - ['=ADDRESS(1,1,3)'], - ['=ADDRESS(1,1,4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('$A$1') - expect(engine.getCellValue(adr('A2'))).toEqual('A$1') - expect(engine.getCellValue(adr('A3'))).toEqual('$A1') - expect(engine.getCellValue(adr('A4'))).toEqual('A1') - }) - - it('with row, col, and abs (R1C1 Notation)', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1,1,1,FALSE())'], - ['=ADDRESS(1,1,2,FALSE())'], - ['=ADDRESS(1,1,3,FALSE())'], - ['=ADDRESS(1,1,4,FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('R1C1') - expect(engine.getCellValue(adr('A2'))).toEqual('R1C[1]') - expect(engine.getCellValue(adr('A3'))).toEqual('R[1]C1') - expect(engine.getCellValue(adr('A4'))).toEqual('R[1]C[1]') - }) - - it('with row, col, abs, and sheetName (A1 Notation)', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1,1,1, TRUE(), "Sheet1")'], - ['=ADDRESS(1,1,2, TRUE(), "Sheet2")'], - ['=ADDRESS(1,1,3, TRUE(), "Sheet3")'], - ['=ADDRESS(1,1,4, TRUE(), "Sheet4")'], - ['=ADDRESS(1,1,4, TRUE(), "")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('Sheet1!$A$1') - expect(engine.getCellValue(adr('A2'))).toEqual('Sheet2!A$1') - expect(engine.getCellValue(adr('A3'))).toEqual('Sheet3!$A1') - expect(engine.getCellValue(adr('A4'))).toEqual('Sheet4!A1') - expect(engine.getCellValue(adr('A5'))).toEqual('!A1') - }) - - it('with row, col, abs, and sheetName (R1C1 Notation)', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1,1,1, FALSE(), "Sheet1")'], - ['=ADDRESS(1,1,2, FALSE(), "Sheet2")'], - ['=ADDRESS(1,1,3, FALSE(), "Sheet3")'], - ['=ADDRESS(1,1,4, FALSE(), "Sheet4")'], - ['=ADDRESS(1,1,4, FALSE(), "")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('Sheet1!R1C1') - expect(engine.getCellValue(adr('A2'))).toEqual('Sheet2!R1C[1]') - expect(engine.getCellValue(adr('A3'))).toEqual('Sheet3!R[1]C1') - expect(engine.getCellValue(adr('A4'))).toEqual('Sheet4!R[1]C[1]') - expect(engine.getCellValue(adr('A5'))).toEqual('!R[1]C[1]') - }) - - it('invalid arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS()'], - ['=ADDRESS(1)'], - ['=ADDRESS(0,0)'], - ['=ADDRESS("row1","row2")'], - ['=ADDRESS(1,1,0)'], - ['=ADDRESS(1,1,5)'], - ['=ADDRESS(1,1,1, true, "")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('true'))) - }) -}) - -describe('ADDRESS - Compatability Checks', () => { - it('row negative - col negative', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(-1, -1, 1, FALSE())'], - ['=ADDRESS(-1, -1, 1, TRUE())'], - ['=ADDRESS(-1, -1, 2, FALSE())'], - ['=ADDRESS(-1, -1, 2, TRUE())'], - ['=ADDRESS(-1, -1, 3, FALSE())'], - ['=ADDRESS(-1, -1, 3, TRUE())'], - ['=ADDRESS(-1, -1, 4, FALSE())'], - ['=ADDRESS(-1, -1, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('R[-1]C[-1]') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row negative - col zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(-1, 0, 1, FALSE())'], - ['=ADDRESS(-1, 0, 1, TRUE())'], - ['=ADDRESS(-1, 0, 2, FALSE())'], - ['=ADDRESS(-1, 0, 2, TRUE())'], - ['=ADDRESS(-1, 0, 3, FALSE())'], - ['=ADDRESS(-1, 0, 3, TRUE())'], - ['=ADDRESS(-1, 0, 4, FALSE())'], - ['=ADDRESS(-1, 0, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('R[-1]C') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row negative - col one', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(-1, 1, 1, FALSE())'], - ['=ADDRESS(-1, 1, 1, TRUE())'], - ['=ADDRESS(-1, 1, 2, FALSE())'], - ['=ADDRESS(-1, 1, 2, TRUE())'], - ['=ADDRESS(-1, 1, 3, FALSE())'], - ['=ADDRESS(-1, 1, 3, TRUE())'], - ['=ADDRESS(-1, 1, 4, FALSE())'], - ['=ADDRESS(-1, 1, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqual('R[-1]C1') - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('R[-1]C[1]') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row zero - col negative', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(0, -1, 1, FALSE())'], - ['=ADDRESS(0, -1, 1, TRUE())'], - ['=ADDRESS(0, -1, 2, FALSE())'], - ['=ADDRESS(0, -1, 2, TRUE())'], - ['=ADDRESS(0, -1, 3, FALSE())'], - ['=ADDRESS(0, -1, 3, TRUE())'], - ['=ADDRESS(0, -1, 4, FALSE())'], - ['=ADDRESS(0, -1, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('RC[-1]') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row zero - col zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(0, 0, 1, FALSE())'], - ['=ADDRESS(0, 0, 1, TRUE())'], - ['=ADDRESS(0, 0, 2, FALSE())'], - ['=ADDRESS(0, 0, 2, TRUE())'], - ['=ADDRESS(0, 0, 3, FALSE())'], - ['=ADDRESS(0, 0, 3, TRUE())'], - ['=ADDRESS(0, 0, 4, FALSE())'], - ['=ADDRESS(0, 0, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('RC') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row zero - col one', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(0, 1, 1, FALSE())'], - ['=ADDRESS(0, 1, 1, TRUE())'], - ['=ADDRESS(0, 1, 2, FALSE())'], - ['=ADDRESS(0, 1, 2, TRUE())'], - ['=ADDRESS(0, 1, 3, FALSE())'], - ['=ADDRESS(0, 1, 3, TRUE())'], - ['=ADDRESS(0, 1, 4, FALSE())'], - ['=ADDRESS(0, 1, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqual('RC1') - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('RC[1]') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row one - col negative', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1, -1, 1, FALSE())'], - ['=ADDRESS(1, -1, 1, TRUE())'], - ['=ADDRESS(1, -1, 2, FALSE())'], - ['=ADDRESS(1, -1, 2, TRUE())'], - ['=ADDRESS(1, -1, 3, FALSE())'], - ['=ADDRESS(1, -1, 3, TRUE())'], - ['=ADDRESS(1, -1, 4, FALSE())'], - ['=ADDRESS(1, -1, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqual('R1C[-1]') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('R[1]C[-1]') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row one - col zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1, 0, 1, FALSE())'], - ['=ADDRESS(1, 0, 1, TRUE())'], - ['=ADDRESS(1, 0, 2, FALSE())'], - ['=ADDRESS(1, 0, 2, TRUE())'], - ['=ADDRESS(1, 0, 3, FALSE())'], - ['=ADDRESS(1, 0, 3, TRUE())'], - ['=ADDRESS(1, 0, 4, FALSE())'], - ['=ADDRESS(1, 0, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqual('R1C') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A7'))).toEqual('R[1]C') - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('row one - col one', () => { - const engine = HyperFormula.buildFromArray([ - ['=ADDRESS(1, 1, 1, FALSE())'], - ['=ADDRESS(1, 1, 1, TRUE())'], - ['=ADDRESS(1, 1, 2, FALSE())'], - ['=ADDRESS(1, 1, 2, TRUE())'], - ['=ADDRESS(1, 1, 3, FALSE())'], - ['=ADDRESS(1, 1, 3, TRUE())'], - ['=ADDRESS(1, 1, 4, FALSE())'], - ['=ADDRESS(1, 1, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('R1C1') - expect(engine.getCellValue(adr('A2'))).toEqual('$A$1') - expect(engine.getCellValue(adr('A3'))).toEqual('R1C[1]') - expect(engine.getCellValue(adr('A4'))).toEqual('A$1') - expect(engine.getCellValue(adr('A5'))).toEqual('R[1]C1') - expect(engine.getCellValue(adr('A6'))).toEqual('$A1') - expect(engine.getCellValue(adr('A7'))).toEqual('R[1]C[1]') - expect(engine.getCellValue(adr('A8'))).toEqual('A1') - }) -}) diff --git a/test/unit/interpreter/function-and.spec.ts b/test/unit/interpreter/function-and.spec.ts deleted file mode 100644 index 2d41dded20..0000000000 --- a/test/unit/interpreter/function-and.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function AND', () => { - it('usage', () => { - const engine = HyperFormula.buildFromArray([ - ['=AND(TRUE(), TRUE())', '=AND(TRUE(), FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=AND(1)', '=AND(0)', '=AND(1, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('use coercion #1', () => { - const engine = HyperFormula.buildFromArray([ - ['=AND("TRUE", 1)'], - ['=AND("foo", TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('use coercion #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=AND(A4:B4)'], - ['=AND(C4:D4)'], - ['=AND(C4:D4, "foo")'], - ['TRUE', 1, 'foo', '=TRUE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('if error in range found, returns first one in row-by-row order', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '1'], - ['=AND(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['1', '1'], - ['=AND(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(true) - }) - - it('takes at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=AND()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('is computed eagerly', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '=4/0'], - ['1', '1'], - ['=AND(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when called with a range, ignores strings other than "true", "false" and ""', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', '=TRUE()', '=AND(A1:B1)'], - ['foo', '=FALSE()', '=AND(A2:B2)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(true) - expect(engine.getCellValue(adr('C2'))).toEqual(false) - }) -}) diff --git a/test/unit/interpreter/function-arabic.spec.ts b/test/unit/interpreter/function-arabic.spec.ts deleted file mode 100644 index 1750abe4c4..0000000000 --- a/test/unit/interpreter/function-arabic.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ARABIC', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARABIC()', '=ARABIC(1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should properly sanitize input', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARABIC(" XD ")'], - ['=ARABIC("xd")'], - ['=ARABIC(" xD ")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(490) - expect(engine.getCellValue(adr('A2'))).toEqual(490) - expect(engine.getCellValue(adr('A3'))).toEqual(490) - }) - - it('should detect incorrect numerals', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARABIC("IMM")'], - ['=ARABIC("MMMM")'], - ['=ARABIC("IXC")'], - ['=ARABIC("--I")'], - ['=ARABIC("-")'], - ['=ARABIC("Ma")'], - ['=ARABIC("M M")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidRoman)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidRoman)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidRoman)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidRoman)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidRoman)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidRoman)) - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidRoman)) - }) - - it('works for border cases', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARABIC("MMMIMIDCCCICILXXXIXIVIII")'], - ['=ARABIC("-I")'], - ['=ARABIC(" ")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(4992) - expect(engine.getCellValue(adr('A2'))).toEqual(-1) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('should output correct value for roman numerals from mode 0', () => { - const [input, output] = inputOutput(0) - const engine = HyperFormula.buildFromArray([input]) - expect(engine.getSheetValues(0)).toEqual([output]) - }) - - it('should output correct value for roman numerals from mode 1', () => { - const [input, output] = inputOutput(1) - const engine = HyperFormula.buildFromArray([input]) - expect(engine.getSheetValues(0)).toEqual([output]) - }) - - it('should output correct value for roman numerals from mode 2', () => { - const [input, output] = inputOutput(2) - const engine = HyperFormula.buildFromArray([input]) - expect(engine.getSheetValues(0)).toEqual([output]) - }) - - it('should output correct value for roman numerals from mode 3', () => { - const [input, output] = inputOutput(0) - const engine = HyperFormula.buildFromArray([input]) - expect(engine.getSheetValues(0)).toEqual([output]) - }) - - it('should output correct value for roman numerals from mode 4', () => { - const [input, output] = inputOutput(4) - const engine = HyperFormula.buildFromArray([input]) - expect(engine.getSheetValues(0)).toEqual([output]) - }) -}) - -function inputOutput(mode: number) { - const arr = [mode0, mode1, mode2, mode3, mode4][mode] - const input = [] - const output = [] - for (let i = 0; i < arr.length; i++) { - input.push(`=ARABIC("${arr[i]}")`) - output.push(i + 1) - } - return [input, output] -} - -const mode0 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'XLV', 'XLVI', 'XLVII', 'XLVIII', 'XLIX', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'XCV', 'XCVI', 'XCVII', 'XCVIII', 'XCIX', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CXLV', 'CXLVI', 'CXLVII', 'CXLVIII', 'CXLIX', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CXCV', 'CXCVI', 'CXCVII', 'CXCVIII', 'CXCIX', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCXLV', 'CCXLVI', 'CCXLVII', 'CCXLVIII', 'CCXLIX', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCXCV', 'CCXCVI', 'CCXCVII', 'CCXCVIII', 'CCXCIX', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCXLV', 'CCCXLVI', 'CCCXLVII', 'CCCXLVIII', 'CCCXLIX', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCXCV', 'CCCXCVI', 'CCCXCVII', 'CCCXCVIII', 'CCCXCIX', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDXLV', 'CDXLVI', 'CDXLVII', 'CDXLVIII', 'CDXLIX', 'CDL', 'CDLI', 'CDLII', 'CDLIII', 'CDLIV', 'CDLV', 'CDLVI', 'CDLVII', 'CDLVIII', 'CDLIX', 'CDLX', 'CDLXI', 'CDLXII', 'CDLXIII', 'CDLXIV', 'CDLXV', 'CDLXVI', 'CDLXVII', 'CDLXVIII', 'CDLXIX', 'CDLXX', 'CDLXXI', 'CDLXXII', 'CDLXXIII', 'CDLXXIV', 'CDLXXV', 'CDLXXVI', 'CDLXXVII', 'CDLXXVIII', 'CDLXXIX', 'CDLXXX', 'CDLXXXI', 'CDLXXXII', 'CDLXXXIII', 'CDLXXXIV', 'CDLXXXV', 'CDLXXXVI', 'CDLXXXVII', 'CDLXXXVIII', 'CDLXXXIX', 'CDXC', 'CDXCI', 'CDXCII', 'CDXCIII', 'CDXCIV', 'CDXCV', 'CDXCVI', 'CDXCVII', 'CDXCVIII', 'CDXCIX', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DXLV', 'DXLVI', 'DXLVII', 'DXLVIII', 'DXLIX', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DXCV', 'DXCVI', 'DXCVII', 'DXCVIII', 'DXCIX', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCXLV', 'DCXLVI', 'DCXLVII', 'DCXLVIII', 'DCXLIX', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCXCV', 'DCXCVI', 'DCXCVII', 'DCXCVIII', 'DCXCIX', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCXLV', 'DCCXLVI', 'DCCXLVII', 'DCCXLVIII', 'DCCXLIX', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCXCV', 'DCCXCVI', 'DCCXCVII', 'DCCXCVIII', 'DCCXCIX', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCXLV', 'DCCCXLVI', 'DCCCXLVII', 'DCCCXLVIII', 'DCCCXLIX', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCXCV', 'DCCCXCVI', 'DCCCXCVII', 'DCCCXCVIII', 'DCCCXCIX', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMXLV', 'CMXLVI', 'CMXLVII', 'CMXLVIII', 'CMXLIX', 'CML', 'CMLI', 'CMLII', 'CMLIII', 'CMLIV', 'CMLV', 'CMLVI', 'CMLVII', 'CMLVIII', 'CMLIX', 'CMLX', 'CMLXI', 'CMLXII', 'CMLXIII', 'CMLXIV', 'CMLXV', 'CMLXVI', 'CMLXVII', 'CMLXVIII', 'CMLXIX', 'CMLXX', 'CMLXXI', 'CMLXXII', 'CMLXXIII', 'CMLXXIV', 'CMLXXV', 'CMLXXVI', 'CMLXXVII', 'CMLXXVIII', 'CMLXXIX', 'CMLXXX', 'CMLXXXI', 'CMLXXXII', 'CMLXXXIII', 'CMLXXXIV', 'CMLXXXV', 'CMLXXXVI', 'CMLXXXVII', 'CMLXXXVIII', 'CMLXXXIX', 'CMXC', 'CMXCI', 'CMXCII', 'CMXCIII', 'CMXCIV', 'CMXCV', 'CMXCVI', 'CMXCVII', 'CMXCVIII', 'CMXCIX', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MXLV', 'MXLVI', 'MXLVII', 'MXLVIII', 'MXLIX', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MXCV', 'MXCVI', 'MXCVII', 'MXCVIII', 'MXCIX', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCXLV', 'MCXLVI', 'MCXLVII', 'MCXLVIII', 'MCXLIX', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCXCV', 'MCXCVI', 'MCXCVII', 'MCXCVIII', 'MCXCIX', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCXLV', 'MCCXLVI', 'MCCXLVII', 'MCCXLVIII', 'MCCXLIX', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCXCV', 'MCCXCVI', 'MCCXCVII', 'MCCXCVIII', 'MCCXCIX', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCXLV', 'MCCCXLVI', 'MCCCXLVII', 'MCCCXLVIII', 'MCCCXLIX', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCXCV', 'MCCCXCVI', 'MCCCXCVII', 'MCCCXCVIII', 'MCCCXCIX', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDXLV', 'MCDXLVI', 'MCDXLVII', 'MCDXLVIII', 'MCDXLIX', 'MCDL', 'MCDLI', 'MCDLII', 'MCDLIII', 'MCDLIV', 'MCDLV', 'MCDLVI', 'MCDLVII', 'MCDLVIII', 'MCDLIX', 'MCDLX', 'MCDLXI', 'MCDLXII', 'MCDLXIII', 'MCDLXIV', 'MCDLXV', 'MCDLXVI', 'MCDLXVII', 'MCDLXVIII', 'MCDLXIX', 'MCDLXX', 'MCDLXXI', 'MCDLXXII', 'MCDLXXIII', 'MCDLXXIV', 'MCDLXXV', 'MCDLXXVI', 'MCDLXXVII', 'MCDLXXVIII', 'MCDLXXIX', 'MCDLXXX', 'MCDLXXXI', 'MCDLXXXII', 'MCDLXXXIII', 'MCDLXXXIV', 'MCDLXXXV', 'MCDLXXXVI', 'MCDLXXXVII', 'MCDLXXXVIII', 'MCDLXXXIX', 'MCDXC', 'MCDXCI', 'MCDXCII', 'MCDXCIII', 'MCDXCIV', 'MCDXCV', 'MCDXCVI', 'MCDXCVII', 'MCDXCVIII', 'MCDXCIX', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDXLV', 'MDXLVI', 'MDXLVII', 'MDXLVIII', 'MDXLIX', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDXCV', 'MDXCVI', 'MDXCVII', 'MDXCVIII', 'MDXCIX', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCXLV', 'MDCXLVI', 'MDCXLVII', 'MDCXLVIII', 'MDCXLIX', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCXCV', 'MDCXCVI', 'MDCXCVII', 'MDCXCVIII', 'MDCXCIX', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCXLV', 'MDCCXLVI', 'MDCCXLVII', 'MDCCXLVIII', 'MDCCXLIX', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCXCV', 'MDCCXCVI', 'MDCCXCVII', 'MDCCXCVIII', 'MDCCXCIX', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCXLV', 'MDCCCXLVI', 'MDCCCXLVII', 'MDCCCXLVIII', 'MDCCCXLIX', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCXCV', 'MDCCCXCVI', 'MDCCCXCVII', 'MDCCCXCVIII', 'MDCCCXCIX', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMXLV', 'MCMXLVI', 'MCMXLVII', 'MCMXLVIII', 'MCMXLIX', 'MCML', 'MCMLI', 'MCMLII', 'MCMLIII', 'MCMLIV', 'MCMLV', 'MCMLVI', 'MCMLVII', 'MCMLVIII', 'MCMLIX', 'MCMLX', 'MCMLXI', 'MCMLXII', 'MCMLXIII', 'MCMLXIV', 'MCMLXV', 'MCMLXVI', 'MCMLXVII', 'MCMLXVIII', 'MCMLXIX', 'MCMLXX', 'MCMLXXI', 'MCMLXXII', 'MCMLXXIII', 'MCMLXXIV', 'MCMLXXV', 'MCMLXXVI', 'MCMLXXVII', 'MCMLXXVIII', 'MCMLXXIX', 'MCMLXXX', 'MCMLXXXI', 'MCMLXXXII', 'MCMLXXXIII', 'MCMLXXXIV', 'MCMLXXXV', 'MCMLXXXVI', 'MCMLXXXVII', 'MCMLXXXVIII', 'MCMLXXXIX', 'MCMXC', 'MCMXCI', 'MCMXCII', 'MCMXCIII', 'MCMXCIV', 'MCMXCV', 'MCMXCVI', 'MCMXCVII', 'MCMXCVIII', 'MCMXCIX', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMXLV', 'MMXLVI', 'MMXLVII', 'MMXLVIII', 'MMXLIX', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMXCV', 'MMXCVI', 'MMXCVII', 'MMXCVIII', 'MMXCIX', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCXLV', 'MMCXLVI', 'MMCXLVII', 'MMCXLVIII', 'MMCXLIX', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCXCV', 'MMCXCVI', 'MMCXCVII', 'MMCXCVIII', 'MMCXCIX', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCXLV', 'MMCCXLVI', 'MMCCXLVII', 'MMCCXLVIII', 'MMCCXLIX', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCXCV', 'MMCCXCVI', 'MMCCXCVII', 'MMCCXCVIII', 'MMCCXCIX', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCXLV', 'MMCCCXLVI', 'MMCCCXLVII', 'MMCCCXLVIII', 'MMCCCXLIX', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCXCV', 'MMCCCXCVI', 'MMCCCXCVII', 'MMCCCXCVIII', 'MMCCCXCIX', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDXLV', 'MMCDXLVI', 'MMCDXLVII', 'MMCDXLVIII', 'MMCDXLIX', 'MMCDL', 'MMCDLI', 'MMCDLII', 'MMCDLIII', 'MMCDLIV', 'MMCDLV', 'MMCDLVI', 'MMCDLVII', 'MMCDLVIII', 'MMCDLIX', 'MMCDLX', 'MMCDLXI', 'MMCDLXII', 'MMCDLXIII', 'MMCDLXIV', 'MMCDLXV', 'MMCDLXVI', 'MMCDLXVII', 'MMCDLXVIII', 'MMCDLXIX', 'MMCDLXX', 'MMCDLXXI', 'MMCDLXXII', 'MMCDLXXIII', 'MMCDLXXIV', 'MMCDLXXV', 'MMCDLXXVI', 'MMCDLXXVII', 'MMCDLXXVIII', 'MMCDLXXIX', 'MMCDLXXX', 'MMCDLXXXI', 'MMCDLXXXII', 'MMCDLXXXIII', 'MMCDLXXXIV', 'MMCDLXXXV', 'MMCDLXXXVI', 'MMCDLXXXVII', 'MMCDLXXXVIII', 'MMCDLXXXIX', 'MMCDXC', 'MMCDXCI', 'MMCDXCII', 'MMCDXCIII', 'MMCDXCIV', 'MMCDXCV', 'MMCDXCVI', 'MMCDXCVII', 'MMCDXCVIII', 'MMCDXCIX', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDXLV', 'MMDXLVI', 'MMDXLVII', 'MMDXLVIII', 'MMDXLIX', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDXCV', 'MMDXCVI', 'MMDXCVII', 'MMDXCVIII', 'MMDXCIX', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCXLV', 'MMDCXLVI', 'MMDCXLVII', 'MMDCXLVIII', 'MMDCXLIX', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCXCV', 'MMDCXCVI', 'MMDCXCVII', 'MMDCXCVIII', 'MMDCXCIX', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCXLV', 'MMDCCXLVI', 'MMDCCXLVII', 'MMDCCXLVIII', 'MMDCCXLIX', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCXCV', 'MMDCCXCVI', 'MMDCCXCVII', 'MMDCCXCVIII', 'MMDCCXCIX', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCXLV', 'MMDCCCXLVI', 'MMDCCCXLVII', 'MMDCCCXLVIII', 'MMDCCCXLIX', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCXCV', 'MMDCCCXCVI', 'MMDCCCXCVII', 'MMDCCCXCVIII', 'MMDCCCXCIX', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMXLV', 'MMCMXLVI', 'MMCMXLVII', 'MMCMXLVIII', 'MMCMXLIX', 'MMCML', 'MMCMLI', 'MMCMLII', 'MMCMLIII', 'MMCMLIV', 'MMCMLV', 'MMCMLVI', 'MMCMLVII', 'MMCMLVIII', 'MMCMLIX', 'MMCMLX', 'MMCMLXI', 'MMCMLXII', 'MMCMLXIII', 'MMCMLXIV', 'MMCMLXV', 'MMCMLXVI', 'MMCMLXVII', 'MMCMLXVIII', 'MMCMLXIX', 'MMCMLXX', 'MMCMLXXI', 'MMCMLXXII', 'MMCMLXXIII', 'MMCMLXXIV', 'MMCMLXXV', 'MMCMLXXVI', 'MMCMLXXVII', 'MMCMLXXVIII', 'MMCMLXXIX', 'MMCMLXXX', 'MMCMLXXXI', 'MMCMLXXXII', 'MMCMLXXXIII', 'MMCMLXXXIV', 'MMCMLXXXV', 'MMCMLXXXVI', 'MMCMLXXXVII', 'MMCMLXXXVIII', 'MMCMLXXXIX', 'MMCMXC', 'MMCMXCI', 'MMCMXCII', 'MMCMXCIII', 'MMCMXCIV', 'MMCMXCV', 'MMCMXCVI', 'MMCMXCVII', 'MMCMXCVIII', 'MMCMXCIX', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMXLV', 'MMMXLVI', 'MMMXLVII', 'MMMXLVIII', 'MMMXLIX', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMXCV', 'MMMXCVI', 'MMMXCVII', 'MMMXCVIII', 'MMMXCIX', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCXLV', 'MMMCXLVI', 'MMMCXLVII', 'MMMCXLVIII', 'MMMCXLIX', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCXCV', 'MMMCXCVI', 'MMMCXCVII', 'MMMCXCVIII', 'MMMCXCIX', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCXLV', 'MMMCCXLVI', 'MMMCCXLVII', 'MMMCCXLVIII', 'MMMCCXLIX', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCXCV', 'MMMCCXCVI', 'MMMCCXCVII', 'MMMCCXCVIII', 'MMMCCXCIX', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCXLV', 'MMMCCCXLVI', 'MMMCCCXLVII', 'MMMCCCXLVIII', 'MMMCCCXLIX', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCXCV', 'MMMCCCXCVI', 'MMMCCCXCVII', 'MMMCCCXCVIII', 'MMMCCCXCIX', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDXLV', 'MMMCDXLVI', 'MMMCDXLVII', 'MMMCDXLVIII', 'MMMCDXLIX', 'MMMCDL', 'MMMCDLI', 'MMMCDLII', 'MMMCDLIII', 'MMMCDLIV', 'MMMCDLV', 'MMMCDLVI', 'MMMCDLVII', 'MMMCDLVIII', 'MMMCDLIX', 'MMMCDLX', 'MMMCDLXI', 'MMMCDLXII', 'MMMCDLXIII', 'MMMCDLXIV', 'MMMCDLXV', 'MMMCDLXVI', 'MMMCDLXVII', 'MMMCDLXVIII', 'MMMCDLXIX', 'MMMCDLXX', 'MMMCDLXXI', 'MMMCDLXXII', 'MMMCDLXXIII', 'MMMCDLXXIV', 'MMMCDLXXV', 'MMMCDLXXVI', 'MMMCDLXXVII', 'MMMCDLXXVIII', 'MMMCDLXXIX', 'MMMCDLXXX', 'MMMCDLXXXI', 'MMMCDLXXXII', 'MMMCDLXXXIII', 'MMMCDLXXXIV', 'MMMCDLXXXV', 'MMMCDLXXXVI', 'MMMCDLXXXVII', 'MMMCDLXXXVIII', 'MMMCDLXXXIX', 'MMMCDXC', 'MMMCDXCI', 'MMMCDXCII', 'MMMCDXCIII', 'MMMCDXCIV', 'MMMCDXCV', 'MMMCDXCVI', 'MMMCDXCVII', 'MMMCDXCVIII', 'MMMCDXCIX', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDXLV', 'MMMDXLVI', 'MMMDXLVII', 'MMMDXLVIII', 'MMMDXLIX', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDXCV', 'MMMDXCVI', 'MMMDXCVII', 'MMMDXCVIII', 'MMMDXCIX', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCXLV', 'MMMDCXLVI', 'MMMDCXLVII', 'MMMDCXLVIII', 'MMMDCXLIX', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCXCV', 'MMMDCXCVI', 'MMMDCXCVII', 'MMMDCXCVIII', 'MMMDCXCIX', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCXLV', 'MMMDCCXLVI', 'MMMDCCXLVII', 'MMMDCCXLVIII', 'MMMDCCXLIX', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCXCV', 'MMMDCCXCVI', 'MMMDCCXCVII', 'MMMDCCXCVIII', 'MMMDCCXCIX', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCXLV', 'MMMDCCCXLVI', 'MMMDCCCXLVII', 'MMMDCCCXLVIII', 'MMMDCCCXLIX', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCXCV', 'MMMDCCCXCVI', 'MMMDCCCXCVII', 'MMMDCCCXCVIII', 'MMMDCCCXCIX', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMXLV', 'MMMCMXLVI', 'MMMCMXLVII', 'MMMCMXLVIII', 'MMMCMXLIX', 'MMMCML', 'MMMCMLI', 'MMMCMLII', 'MMMCMLIII', 'MMMCMLIV', 'MMMCMLV', 'MMMCMLVI', 'MMMCMLVII', 'MMMCMLVIII', 'MMMCMLIX', 'MMMCMLX', 'MMMCMLXI', 'MMMCMLXII', 'MMMCMLXIII', 'MMMCMLXIV', 'MMMCMLXV', 'MMMCMLXVI', 'MMMCMLXVII', 'MMMCMLXVIII', 'MMMCMLXIX', 'MMMCMLXX', 'MMMCMLXXI', 'MMMCMLXXII', 'MMMCMLXXIII', 'MMMCMLXXIV', 'MMMCMLXXV', 'MMMCMLXXVI', 'MMMCMLXXVII', 'MMMCMLXXVIII', 'MMMCMLXXIX', 'MMMCMLXXX', 'MMMCMLXXXI', 'MMMCMLXXXII', 'MMMCMLXXXIII', 'MMMCMLXXXIV', 'MMMCMLXXXV', 'MMMCMLXXXVI', 'MMMCMLXXXVII', 'MMMCMLXXXVIII', 'MMMCMLXXXIX', 'MMMCMXC', 'MMMCMXCI', 'MMMCMXCII', 'MMMCMXCIII', 'MMMCMXCIV', 'MMMCMXCV', 'MMMCMXCVI', 'MMMCMXCVII', 'MMMCMXCVIII', 'MMMCMXCIX', ] -const mode1 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'VLIV', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'VCIV', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CVLIV', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CVCIV', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCVLIV', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCVCIV', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCVLIV', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCVCIV', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDVLIV', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'LDXL', 'LDXLI', 'LDXLII', 'LDXLIII', 'LDXLIV', 'LDVL', 'LDVLI', 'LDVLII', 'LDVLIII', 'LDVLIV', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DVLIV', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DVCIV', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCVLIV', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCVCIV', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCVLIV', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCVCIV', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCVLIV', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCVCIV', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMVLIV', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'LMXL', 'LMXLI', 'LMXLII', 'LMXLIII', 'LMXLIV', 'LMVL', 'LMVLI', 'LMVLII', 'LMVLIII', 'LMVLIV', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MVLIV', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MVCIV', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCVLIV', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCVCIV', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCVLIV', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCVCIV', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCVLIV', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCVCIV', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDVLIV', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MLDXL', 'MLDXLI', 'MLDXLII', 'MLDXLIII', 'MLDXLIV', 'MLDVL', 'MLDVLI', 'MLDVLII', 'MLDVLIII', 'MLDVLIV', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDVLIV', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDVCIV', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCVLIV', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCVCIV', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCVLIV', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCVCIV', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCVLIV', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCVCIV', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMVLIV', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MLMXL', 'MLMXLI', 'MLMXLII', 'MLMXLIII', 'MLMXLIV', 'MLMVL', 'MLMVLI', 'MLMVLII', 'MLMVLIII', 'MLMVLIV', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMVLIV', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMVCIV', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCVLIV', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCVCIV', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCVLIV', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCVCIV', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCVLIV', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCVCIV', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDVLIV', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMLDXL', 'MMLDXLI', 'MMLDXLII', 'MMLDXLIII', 'MMLDXLIV', 'MMLDVL', 'MMLDVLI', 'MMLDVLII', 'MMLDVLIII', 'MMLDVLIV', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDVLIV', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDVCIV', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCVLIV', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCVCIV', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCVLIV', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCVCIV', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCVLIV', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCVCIV', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMVLIV', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMLMXL', 'MMLMXLI', 'MMLMXLII', 'MMLMXLIII', 'MMLMXLIV', 'MMLMVL', 'MMLMVLI', 'MMLMVLII', 'MMLMVLIII', 'MMLMVLIV', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMVLIV', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMVCIV', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCVLIV', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCVCIV', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCVLIV', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCVCIV', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCVLIV', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCVCIV', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDVLIV', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMLDXL', 'MMMLDXLI', 'MMMLDXLII', 'MMMLDXLIII', 'MMMLDXLIV', 'MMMLDVL', 'MMMLDVLI', 'MMMLDVLII', 'MMMLDVLIII', 'MMMLDVLIV', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDVLIV', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDVCIV', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCVLIV', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCVCIV', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCVLIV', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCVCIV', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCVLIV', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCVCIV', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMVLIV', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMLMXL', 'MMMLMXLI', 'MMMLMXLII', 'MMMLMXLIII', 'MMMLMXLIV', 'MMMLMVL', 'MMMLMVLI', 'MMMLMVLII', 'MMMLMVLIII', 'MMMLMVLIV', ] -const mode2 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'IL', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'IC', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CIL', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CIC', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCIL', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCIC', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCIL', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCIC', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDIL', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'XD', 'XDI', 'XDII', 'XDIII', 'XDIV', 'XDV', 'XDVI', 'XDVII', 'XDVIII', 'XDIX', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DIL', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DIC', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCIL', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCIC', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCIL', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCIC', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCIL', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCIC', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMIL', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'XM', 'XMI', 'XMII', 'XMIII', 'XMIV', 'XMV', 'XMVI', 'XMVII', 'XMVIII', 'XMIX', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MIL', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MIC', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCIL', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCIC', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCIL', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCIC', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCIL', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCIC', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDIL', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MXD', 'MXDI', 'MXDII', 'MXDIII', 'MXDIV', 'MXDV', 'MXDVI', 'MXDVII', 'MXDVIII', 'MXDIX', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDIL', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDIC', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCIL', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCIC', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCIL', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCIC', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCIL', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCIC', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMIL', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MXM', 'MXMI', 'MXMII', 'MXMIII', 'MXMIV', 'MXMV', 'MXMVI', 'MXMVII', 'MXMVIII', 'MXMIX', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMIL', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMIC', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCIL', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCIC', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCIL', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCIC', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCIL', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCIC', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDIL', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMXD', 'MMXDI', 'MMXDII', 'MMXDIII', 'MMXDIV', 'MMXDV', 'MMXDVI', 'MMXDVII', 'MMXDVIII', 'MMXDIX', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDIL', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDIC', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCIL', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCIC', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCIL', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCIC', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCIL', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCIC', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMIL', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMXM', 'MMXMI', 'MMXMII', 'MMXMIII', 'MMXMIV', 'MMXMV', 'MMXMVI', 'MMXMVII', 'MMXMVIII', 'MMXMIX', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMIL', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMIC', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCIL', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCIC', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCIL', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCIC', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCIL', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCIC', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDIL', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMXD', 'MMMXDI', 'MMMXDII', 'MMMXDIII', 'MMMXDIV', 'MMMXDV', 'MMMXDVI', 'MMMXDVII', 'MMMXDVIII', 'MMMXDIX', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDIL', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDIC', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCIL', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCIC', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCIL', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCIC', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCIL', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCIC', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMIL', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMXM', 'MMMXMI', 'MMMXMII', 'MMMXMIII', 'MMMXMIV', 'MMMXMV', 'MMMXMVI', 'MMMXMVII', 'MMMXMVIII', 'MMMXMIX', ] -const mode3 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'IL', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'IC', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CIL', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CIC', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCIL', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCIC', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCIL', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCIC', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDIL', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'XD', 'XDI', 'XDII', 'XDIII', 'XDIV', 'VD', 'VDI', 'VDII', 'VDIII', 'VDIV', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DIL', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DIC', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCIL', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCIC', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCIL', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCIC', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCIL', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCIC', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMIL', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'XM', 'XMI', 'XMII', 'XMIII', 'XMIV', 'VM', 'VMI', 'VMII', 'VMIII', 'VMIV', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MIL', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MIC', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCIL', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCIC', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCIL', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCIC', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCIL', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCIC', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDIL', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MXD', 'MXDI', 'MXDII', 'MXDIII', 'MXDIV', 'MVD', 'MVDI', 'MVDII', 'MVDIII', 'MVDIV', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDIL', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDIC', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCIL', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCIC', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCIL', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCIC', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCIL', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCIC', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMIL', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MXM', 'MXMI', 'MXMII', 'MXMIII', 'MXMIV', 'MVM', 'MVMI', 'MVMII', 'MVMIII', 'MVMIV', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMIL', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMIC', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCIL', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCIC', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCIL', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCIC', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCIL', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCIC', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDIL', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMXD', 'MMXDI', 'MMXDII', 'MMXDIII', 'MMXDIV', 'MMVD', 'MMVDI', 'MMVDII', 'MMVDIII', 'MMVDIV', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDIL', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDIC', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCIL', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCIC', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCIL', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCIC', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCIL', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCIC', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMIL', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMXM', 'MMXMI', 'MMXMII', 'MMXMIII', 'MMXMIV', 'MMVM', 'MMVMI', 'MMVMII', 'MMVMIII', 'MMVMIV', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMIL', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMIC', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCIL', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCIC', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCIL', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCIC', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCIL', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCIC', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDIL', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMXD', 'MMMXDI', 'MMMXDII', 'MMMXDIII', 'MMMXDIV', 'MMMVD', 'MMMVDI', 'MMMVDII', 'MMMVDIII', 'MMMVDIV', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDIL', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDIC', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCIL', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCIC', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCIL', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCIC', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCIL', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCIC', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMIL', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMXM', 'MMMXMI', 'MMMXMII', 'MMMXMIII', 'MMMXMIV', 'MMMVM', 'MMMVMI', 'MMMVMII', 'MMMVMIII', 'MMMVMIV', ] -const mode4 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'IL', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'IC', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CIL', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CIC', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCIL', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCIC', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCIL', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCIC', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDIL', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'XD', 'XDI', 'XDII', 'XDIII', 'XDIV', 'VD', 'VDI', 'VDII', 'VDIII', 'ID', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DIL', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DIC', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCIL', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCIC', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCIL', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCIC', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCIL', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCIC', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMIL', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'XM', 'XMI', 'XMII', 'XMIII', 'XMIV', 'VM', 'VMI', 'VMII', 'VMIII', 'IM', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MIL', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MIC', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCIL', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCIC', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCIL', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCIC', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCIL', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCIC', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDIL', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MXD', 'MXDI', 'MXDII', 'MXDIII', 'MXDIV', 'MVD', 'MVDI', 'MVDII', 'MVDIII', 'MID', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDIL', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDIC', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCIL', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCIC', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCIL', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCIC', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCIL', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCIC', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMIL', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MXM', 'MXMI', 'MXMII', 'MXMIII', 'MXMIV', 'MVM', 'MVMI', 'MVMII', 'MVMIII', 'MIM', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMIL', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMIC', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCIL', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCIC', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCIL', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCIC', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCIL', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCIC', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDIL', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMXD', 'MMXDI', 'MMXDII', 'MMXDIII', 'MMXDIV', 'MMVD', 'MMVDI', 'MMVDII', 'MMVDIII', 'MMID', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDIL', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDIC', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCIL', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCIC', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCIL', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCIC', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCIL', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCIC', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMIL', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMXM', 'MMXMI', 'MMXMII', 'MMXMIII', 'MMXMIV', 'MMVM', 'MMVMI', 'MMVMII', 'MMVMIII', 'MMIM', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMIL', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMIC', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCIL', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCIC', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCIL', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCIC', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCIL', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCIC', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDIL', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMXD', 'MMMXDI', 'MMMXDII', 'MMMXDIII', 'MMMXDIV', 'MMMVD', 'MMMVDI', 'MMMVDII', 'MMMVDIII', 'MMMID', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDIL', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDIC', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCIL', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCIC', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCIL', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCIC', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCIL', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCIC', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMIL', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMXM', 'MMMXMI', 'MMMXMII', 'MMMXMIII', 'MMMXMIV', 'MMMVM', 'MMMVMI', 'MMMVMII', 'MMMVMIII', 'MMMIM', ] diff --git a/test/unit/interpreter/function-array_constrain.spec.ts b/test/unit/interpreter/function-array_constrain.spec.ts deleted file mode 100644 index b17ec7ba70..0000000000 --- a/test/unit/interpreter/function-array_constrain.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - function ARRAY_CONSTRAIN', () => { - it('works #1', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAY_CONSTRAIN(1, 1, 1)'], - ]) - expect(engine.getSheetValues(0)).toEqual([[1]]) - }) - - it('works #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAY_CONSTRAIN(1, 2, 2)'], - ]) - expect(engine.getSheetValues(0)).toEqual([[1]]) - }) - - it('validates args', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAY_CONSTRAIN(1, 0, 1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('works #3', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=ARRAY_CONSTRAIN(Sheet2!A1:C3, 2, 2)'], - ], - Sheet2: [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ] - }) - expect(engine.getSheetValues(0)).toEqual([[1, 2], [4, 5]]) - }) - - it('works #4', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['=ARRAY_CONSTRAIN(Sheet2!A1:C3, 2, 4)'], - ], - Sheet2: [ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ] - }) - expect(engine.getSheetValues(0)).toEqual([[1, 2, 3], [4, 5, 6]]) - }) - - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAY_CONSTRAIN(1, 2)'], - ['=ARRAY_CONSTRAIN(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) -}) diff --git a/test/unit/interpreter/function-arrayformula.spec.ts b/test/unit/interpreter/function-arrayformula.spec.ts deleted file mode 100644 index bd25faf935..0000000000 --- a/test/unit/interpreter/function-arrayformula.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - function ARRAYFORMULA', () => { - it('works #1', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAYFORMULA(1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('works #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAYFORMULA(1/0)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('enables arrayformulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(ARRAYFORMULA(A2:C2+A2:C2))'], - [1, 2, 3] - ], {useArrayArithmetic: false}) - expect(engine.getCellValue(adr('A1'))).toEqual(12) - }) - - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ARRAYFORMULA()'], - ['=ARRAYFORMULA(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) -}) diff --git a/test/unit/interpreter/function-asin.spec.ts b/test/unit/interpreter/function-asin.spec.ts deleted file mode 100644 index d1ac087e49..0000000000 --- a/test/unit/interpreter/function-asin.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ASIN', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ASIN(0)', '=ASIN(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.523598775598299) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ASIN("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('for 1 (edge)', () => { - const engine = HyperFormula.buildFromArray([['=ASIN(1)']], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toBe(Math.PI / 2) - }) - - it('for -1 (edge)', () => { - const engine = HyperFormula.buildFromArray([['=ASIN(-1)']], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(-Math.PI / 2) - }) - - it('when value too large', () => { - const engine = HyperFormula.buildFromArray([['=ASIN(1.1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('when value too small', () => { - const engine = HyperFormula.buildFromArray([['=ASIN(-1.1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ASIN()', '=ASIN(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=ASIN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-Math.PI / 2) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ASIN(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-asinh.spec.ts b/test/unit/interpreter/function-asinh.spec.ts deleted file mode 100644 index fc63d67680..0000000000 --- a/test/unit/interpreter/function-asinh.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ASINH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ASINH(0)', '=ASINH(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.481211825059604) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ASINH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ASINH()', '=ASINH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=ASINH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.881373587019543) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ASINH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-atan.spec.ts b/test/unit/interpreter/function-atan.spec.ts deleted file mode 100644 index a9ce9fa24e..0000000000 --- a/test/unit/interpreter/function-atan.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ATAN', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ATAN(1)']], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toBe(0.7853981633974483) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ATAN("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ATAN()', '=ATAN(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=ATAN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.785398163397448) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ATAN(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-atan2.spec.ts b/test/unit/interpreter/function-atan2.spec.ts deleted file mode 100644 index d29dedfaae..0000000000 --- a/test/unit/interpreter/function-atan2.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ATAN2', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ATAN2(1, 2)']], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.107148718, 6) - }) - - it('validates error', () => { - const engine = HyperFormula.buildFromArray([['=ATAN2(0, 0)']], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ATAN2(1,"foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ATAN2()', '=ATAN2(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '="1"', '=ATAN2(A1,B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(2.35619449019234) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ATAN2(4/0, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-atanh.spec.ts b/test/unit/interpreter/function-atanh.spec.ts deleted file mode 100644 index b67a2cafb5..0000000000 --- a/test/unit/interpreter/function-atanh.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ATANH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=ATANH(0)', '=ATANH(0.5)']], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.5493061443340548) - }) - - it('error for 1', () => { - const engine = HyperFormula.buildFromArray([['=ATANH(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('error for -1', () => { - const engine = HyperFormula.buildFromArray([['=ATANH(-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=ATANH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=ATANH()', '=ATANH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="0"', '=ATANH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ATANH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-avedev.spec.ts b/test/unit/interpreter/function-avedev.spec.ts deleted file mode 100644 index 71cc7cced3..0000000000 --- a/test/unit/interpreter/function-avedev.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {adr, detailedError} from '../testUtils' - -describe('Function AVEDEV', () => { - it('single number', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVEDEV(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('two numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVEDEV(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) - - it('more numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVEDEV(3, 1, 2, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1.2) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '9', '0'], - ['=AVEDEV(A1:C1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(4) - }) - - it('propagates error from regular argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=AVEDEV(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('propagates first error from range argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=FOO(', '=AVEDEV(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('returns error for empty ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVEDEV(A2:A3)'], - [null], - [null], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - /** - * Product #1 returns 0 - */ - it('does coercions of nonnumeric explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVEDEV(TRUE(),FALSE(),)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.444444444444444, 6) - }) - - /** - * Product #2 returns 0.2: - * average is computed from numbers, but sum of distances to avg is divided by the original range size. - */ - it('ignores nonnumeric values in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVEDEV(A2:E2)'], - [0, 1, false, null, '\'0'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) -}) diff --git a/test/unit/interpreter/function-average.spec.ts b/test/unit/interpreter/function-average.spec.ts deleted file mode 100644 index f82b381ecc..0000000000 --- a/test/unit/interpreter/function-average.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('AVERAGE', () => { - it('AVERAGE with empty args', () => { - const engine = HyperFormula.buildFromArray([['=AVERAGE()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('AVERAGE with args', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGE(1, B1)', '4'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2.5) - }) - - it('AVERAGE with range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['4'], - ['=AVERAGE(A1:A3)'] - ]) - - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(2.333333333) - }) - - it('AVERAGE ignores all nonnumeric arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['foo'], - [null], - ['=TRUE()'], - ['=AVERAGE(A1:A4)'] - ]) - - expect(engine.getCellValue(adr('A5'))).toEqual(42) - }) - - it('error when no meaningful arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - [null], - ['=AVERAGE(A1:A2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=AVERAGE(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(13.5) - }) - - it('does propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=AVERAGE(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-averagea.spec.ts b/test/unit/interpreter/function-averagea.spec.ts deleted file mode 100644 index 53b384de4f..0000000000 --- a/test/unit/interpreter/function-averagea.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('AVERAGEA', () => { - it('AVERAGEA with empty args', () => { - const engine = HyperFormula.buildFromArray([['=AVERAGEA()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('AVERAGEA with args', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEA(1, B1)', '4'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2.5) - }) - - it('AVERAGEA with range', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['4'], - ['=AVERAGEA(A1:A3)'] - ]) - - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(2.333333333) - }) - - it('AVERAGEA converts non-blank values to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['39', '="1"', '=AVERAGEA(A1:B1)'], - ['39', '=TRUE()', '=AVERAGEA(A2:B2)'], - ['39', null, '=AVERAGEA(A3:B3)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(19.5) - expect(engine.getCellValue(adr('C2'))).toEqual(20) - expect(engine.getCellValue(adr('C3'))).toEqual(39) - }) - - it('error when no meaningful arguments', () => { - const engine = HyperFormula.buildFromArray([ - [null, 'foo'], - [null, null], - ['=AVERAGEA(A1:A2)', '=AVERAGEA(B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B3'))).toEqual(0) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=AVERAGEA(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(13.5) - }) - - it('does propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=AVERAGEA(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-averageif.spec.ts b/test/unit/interpreter/function-averageif.spec.ts deleted file mode 100644 index b6b9fe09d3..0000000000 --- a/test/unit/interpreter/function-averageif.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function AVERAGEIF - argument validations and combinations', () => { - it('requires 2 or 3 arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEIF(C1)'], - ['=AVERAGEIF(C1, ">0", C1, C1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('error when criterion unparsable', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEIF(B1:B2, "> { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEIF(B1:C1, ">0", B2:D2)'], - ['=AVERAGEIF(B1, ">0", B2:D2)'], - ['=AVERAGEIF(B1:D1, ">0", B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('error when different height dimension of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEIF(B1:B2, ">0", C1:C3)'], - ['=AVERAGEIF(B1, ">0", C1:C2)'], - ['=AVERAGEIF(B1:B2, ">0", C1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('error when number of elements match but dimensions doesnt', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEIF(B1:B2, ">0", B1:C1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('scalars are treated like singular arrays', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEIF(10, ">1", 42)'], - ['=AVERAGEIF(0, ">1", 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('no coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="1"'], - ['="foo"'], - [null], - ['=AVERAGEIF(A1:A3, "<>42")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=AVERAGEIF(4/0, ">1", 42)'], - ['=AVERAGEIF(0, 4/0, 42)'], - ['=AVERAGEIF(0, ">1", 4/0)'], - ['=AVERAGEIF(0, 4/0, FOOBAR())'], - ['=AVERAGEIF(4/0, FOOBAR(), 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works when arguments are just references', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=AVERAGEIF(A1, ">1", B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('works with range values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '3', '5'], - ['1', '1', '7', '9'], - ['=AVERAGEIF(MMULT(A1:B2, A1:B2), "=2", MMULT(C1:D2, C1:D2))'], - ['=AVERAGEIF(A1:B2, "=1", MMULT(C1:D2, C1:D2))'], - ['=AVERAGEIF(MMULT(A1:B2, A1:B2), "=2", C1:D2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(76) - expect(engine.getCellValue(adr('A4'))).toEqual(76) - expect(engine.getCellValue(adr('A5'))).toEqual(6) - }) - - it('works for mixed reference/range arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=AVERAGEIF(A1:A1, ">1", B1)'], - ['=AVERAGEIF(A1, ">1", B1:B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('works for 2 arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['10', '20', '30'], - ['=AVERAGEIF(A1:C1, ">15")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(25) - }) - - it('works for matrices', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - [], - ['=AVERAGEIF(A2:A3, ">0", A2:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(1.5) - }) -}) diff --git a/test/unit/interpreter/function-base.spec.ts b/test/unit/interpreter/function-base.spec.ts deleted file mode 100644 index f3d7eadaa7..0000000000 --- a/test/unit/interpreter/function-base.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BASE', () => { - it('should return error when argument of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE("foo")'], - ['=BASE("foo", 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE(1, 2, 3)'], - ['=BASE(2, 5)'], - ['=BASE(23, "10")'], - ['=BASE(254, 15, "9")'], - ['=BASE(634, 33)'], - ['=BASE(789, 36)'], - ['=BASE(1234123412341230, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('001') - expect(engine.getCellValue(adr('A2'))).toEqual('2') - expect(engine.getCellValue(adr('A3'))).toEqual('23') - expect(engine.getCellValue(adr('A4'))).toEqual('00000011E') - expect(engine.getCellValue(adr('A5'))).toEqual('J7') - expect(engine.getCellValue(adr('A6'))).toEqual('LX') - expect(engine.getCellValue(adr('A7'))).toEqual('100011000100110110110111111100110100000000111101110') - }) - - it('should work for numeric strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE("123", 4)'], - ['=BASE("1234", 16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1323') - expect(engine.getCellValue(adr('A2'))).toEqual('4D2') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE(123, 2)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should respect third argument and fill with zeros', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE(2, 8, 3)'], - ['=BASE(94862, "33", 16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('002') - expect(engine.getCellValue(adr('A2'))).toEqual('0000000000002L3K') - }) - - it('should return result as is if padding shorter than result', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE(123, 2, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1111011') - }) - - it('should return error for negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE(-2, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should allow base from 2 to 36', () => { - const engine = HyperFormula.buildFromArray([ - ['=BASE(2, 1)'], - ['=BASE(2, 2)'], - ['=BASE(2, 36)'], - ['=BASE(2, 37)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqual('10') - expect(engine.getCellValue(adr('A3'))).toEqual('2') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-besseli.spec.ts b/test/unit/interpreter/function-besseli.spec.ts deleted file mode 100644 index 38739e0474..0000000000 --- a/test/unit/interpreter/function-besseli.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BESSELI', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELI(1)'], - ['=BESSELI(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELI("foo", 1)'], - ['=BESSELI(2, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELI(-1,0)'], - ['=BESSELI(0,0)'], - ['=BESSELI(5,0)'], - ['=BESSELI(-1,1)'], - ['=BESSELI(0,1)'], - ['=BESSELI(5,1)'], - ['=BESSELI(-1,3)'], - ['=BESSELI(0,3)'], - ['=BESSELI(5,3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.26606584803426, 6) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(27.2398718943949, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(-0.565159097581944, 6) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(24.3356418457055, 6) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(-0.0221684244039833, 6) - expect(engine.getCellValue(adr('A8'))).toEqual(0) - expect(engine.getCellValue(adr('A9'))).toBeCloseTo(10.3311501959992, 6) - }) - - it('should check bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELI(1, -0.001)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - - }) - - it('should truncate second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELI(-1,0.9)'], - ['=BESSELI(0,0.9)'], - ['=BESSELI(5,0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.26606584803426, 6) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(27.2398718943949, 6) - }) -}) diff --git a/test/unit/interpreter/function-besselj.spec.ts b/test/unit/interpreter/function-besselj.spec.ts deleted file mode 100644 index 2503d9eaf3..0000000000 --- a/test/unit/interpreter/function-besselj.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BESSELJ', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELJ(1)'], - ['=BESSELJ(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELJ("foo", 1)'], - ['=BESSELJ(2, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELJ(-1,0)'], - ['=BESSELJ(0,0)'], - ['=BESSELJ(5,0)'], - ['=BESSELJ(-1,1)'], - ['=BESSELJ(0,1)'], - ['=BESSELJ(5,1)'], - ['=BESSELJ(-1,3)'], - ['=BESSELJ(0,3)'], - ['=BESSELJ(5,3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.765197683754859, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.00000000283141, 9) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.177596774112343, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(-0.44005058567713, 6) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(-0.327579138566363, 6) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(-0.019563353982688, 6) - expect(engine.getCellValue(adr('A8'))).toEqual(0) - expect(engine.getCellValue(adr('A9'))).toBeCloseTo(0.364831233515002, 6) - }) - - it('should check bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELJ(1, -0.001)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - - }) - - it('should truncate second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELJ(-1,0.9)'], - ['=BESSELJ(0,0.9)'], - ['=BESSELJ(5,0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.765197683754859, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.00000000283141, 9) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.177596774112343, 6) - }) -}) diff --git a/test/unit/interpreter/function-besselk.spec.ts b/test/unit/interpreter/function-besselk.spec.ts deleted file mode 100644 index 6f0c1861d8..0000000000 --- a/test/unit/interpreter/function-besselk.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BESSELK', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELK(1)'], - ['=BESSELK(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELK("foo", 1)'], - ['=BESSELK(2, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELK(0.1,0)'], - ['=BESSELK(1,0)'], - ['=BESSELK(5,0)'], - ['=BESSELK(0.1,1)'], - ['=BESSELK(1,1)'], - ['=BESSELK(5,1)'], - ['=BESSELK(0.1,3)'], - ['=BESSELK(1,3)'], - ['=BESSELK(5,3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.42706902485802, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.421024421083418, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.00369109838196031, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(9.85384478360091, 6) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(0.601907231666906, 6) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(0.00404461338320827, 6) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(7990.01243265865, 6) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(7.10126276933582, 6) - expect(engine.getCellValue(adr('A9'))).toBeCloseTo(0.00829176837140317, 6) - }) - - it('should check bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELK(1, -0.001)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - - }) - - it('should truncate second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELK(0.1,0.9)'], - ['=BESSELK(1,0.9)'], - ['=BESSELK(5,0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.42706902485802, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.421024421083418, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.00369109838196031, 6) - }) -}) diff --git a/test/unit/interpreter/function-bessely.spec.ts b/test/unit/interpreter/function-bessely.spec.ts deleted file mode 100644 index 4e490a1004..0000000000 --- a/test/unit/interpreter/function-bessely.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BESSELY', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELY(1)'], - ['=BESSELY(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELY("foo", 1)'], - ['=BESSELY(2, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELY(0.1,0)'], - ['=BESSELY(1,0)'], - ['=BESSELY(5,0)'], - ['=BESSELY(0.1,1)'], - ['=BESSELY(1,1)'], - ['=BESSELY(5,1)'], - ['=BESSELY(0.1,3)'], - ['=BESSELY(1,3)'], - ['=BESSELY(5,3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-1.53423866134966, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0882569713977081, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.308517623032057, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(-6.45895109099111, 6) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(-0.78121282095312, 6) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(0.147863139887343, 6) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(-5099.33237524791, 6) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(-5.82151763226267, 6) - expect(engine.getCellValue(adr('A9'))).toBeCloseTo(0.146267163302253, 6) - }) - - it('should check bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELY(1, -0.001)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - - }) - - it('should truncate second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BESSELY(0.1,0.9)'], - ['=BESSELY(1,0.9)'], - ['=BESSELY(5,0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-1.53423866134966, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0882569713977081, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.308517623032057, 6) - }) -}) diff --git a/test/unit/interpreter/function-beta.dist.spec.ts b/test/unit/interpreter/function-beta.dist.spec.ts deleted file mode 100644 index cc50b26b0b..0000000000 --- a/test/unit/interpreter/function-beta.dist.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BETA.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.DIST(1, 2, 3)'], - ['=BETA.DIST(1, 2, 3, 4, 5, 6, 7)'], - ]) - - //product #1 returns 1 - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.DIST("foo", 2, 3, TRUE())'], - ['=BETA.DIST(1, "baz", 3, TRUE())'], - ['=BETA.DIST(1, 2, "baz", TRUE())'], - ['=BETA.DIST(1, 2, 3, "abcd")'], - ['=BETA.DIST(1, 2, 3, TRUE(), "a", 2)'], - ['=BETA.DIST(1, 2, 3, TRUE(), 1, "b")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.DIST(0.1, 1, 2, TRUE())'], - ['=BETA.DIST(0.5, 2, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.19, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.8125, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.DIST(0.1, 1, 2, FALSE())'], - ['=BETA.DIST(0.5, 2, 4, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.8, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.25, 6) - }) - - it('scaling works', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.DIST(1.2, 1, 2, TRUE(), 1, 3)'], - ['=BETA.DIST(15, 2, 4, TRUE(), 10, 20)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.19, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.8125, 6) - }) - - //product #1 returns 0 for tests 1,2,4,5 - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.DIST(0, 1, 1, FALSE())'], - ['=BETA.DIST(1, 0, 1, FALSE())'], - ['=BETA.DIST(1, 1, 0, FALSE())'], - ['=BETA.DIST(0.6, 1, 1, FALSE(), 0.6, 0.7)'], - ['=BETA.DIST(0.7, 1, 1, FALSE(), 0.6, 0.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-beta.inv.spec.ts b/test/unit/interpreter/function-beta.inv.spec.ts deleted file mode 100644 index dabab842cc..0000000000 --- a/test/unit/interpreter/function-beta.inv.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BETA.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.INV(1, 2)'], - ['=BETA.INV(1, 2, 3, 4, 5, 6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.INV("foo", 2, 3)'], - ['=BETA.INV(1, "baz", 3)'], - ['=BETA.INV(1, 2, "baz")'], - ['=BETA.INV(1, 2, 3, "a", 2)'], - ['=BETA.INV(1, 2, 3, 1, "b")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.INV(0.1, 1, 2)'], - ['=BETA.INV(0.5, 2, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0513167019494862, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.313810170455698, 6) - }) - - it('scaling works', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.INV(0.1, 1, 2, 2, 10)'], - ['=BETA.INV(0.5, 2, 4, -1, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.41053361559589, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-0.686189829544302, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BETA.INV(0, 1, 1)'], - ['=BETA.INV(0.5, 0, 1)'], - ['=BETA.INV(0.5, 1, 0)'], - ['=BETA.INV(1, 1, 1)'], - ['=BETA.INV(1.0001, 1, 1)'], - ['=BETA.INV(0.6, 1, 1, 0.7, 0.6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqual(1) //product #2 returns NUM - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WrongOrder)) - }) -}) diff --git a/test/unit/interpreter/function-bin2dec.spec.ts b/test/unit/interpreter/function-bin2dec.spec.ts deleted file mode 100644 index d9874410d8..0000000000 --- a/test/unit/interpreter/function-bin2dec.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BIN2DEC', () => { - it('should work only for one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2DEC(101)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - - it('should not work for non-binary arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2DEC("foo")'], - ['=BIN2DEC(1234)'], - ['=BIN2DEC(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - }) - - it('should work only for 10 bits', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2DEC(10101010101010)'], - ['=BIN2DEC(1010101010)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqual(-342) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2DEC(1111111111)'], - ['=BIN2DEC(1000000000)'], - ['=BIN2DEC(111111111)'], - ['=BIN2DEC(101)'], - ['=BIN2DEC(000101)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-1) - expect(engine.getCellValue(adr('A2'))).toEqual(-512) - expect(engine.getCellValue(adr('A3'))).toEqual(511) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - - }) - - it('should work with references', () => { - const engine = HyperFormula.buildFromArray([ - ['1101'], - ['=BIN2DEC(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(13) - }) - - it('should return numeric type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2DEC(101)'], - ]) - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.NUMBER) - }) -}) diff --git a/test/unit/interpreter/function-bin2hex.spec.ts b/test/unit/interpreter/function-bin2hex.spec.ts deleted file mode 100644 index e37793d263..0000000000 --- a/test/unit/interpreter/function-bin2hex.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BIN2HEX', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-binary arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX("foo")'], - ['=BIN2HEX(1234)'], - ['=BIN2HEX(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX(1)'], - ['=BIN2HEX(10)'], - ['=BIN2HEX(010)'], - ['=BIN2HEX(101110)'], - ['=BIN2HEX(1000000000)'], - ['=BIN2HEX(1111111111)'], - ['=BIN2HEX(111111111)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('2') - expect(engine.getCellValue(adr('A3'))).toEqual('2') - expect(engine.getCellValue(adr('A4'))).toEqual('2E') - expect(engine.getCellValue(adr('A5'))).toEqual('FFFFFFFE00') - expect(engine.getCellValue(adr('A6'))).toEqual('FFFFFFFFFF') - expect(engine.getCellValue(adr('A7'))).toEqual('1FF') - }) - - it('should work for binary strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX("1101")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('D') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="1011"'], - ['=BIN2HEX(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('B') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX(10111)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should work only for 10 bits', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX(10101010101010)'], - ['=BIN2HEX(1010101010)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqual('FFFFFFFEAA') - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX(10, 8)'], - ['=BIN2HEX(101, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00000002') - expect(engine.getCellValue(adr('A2'))).toEqual('0005') - }) - - it('second argument should not affect negative results', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX(1110110100, 1)'], - ['=BIN2HEX(1110110100, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('FFFFFFFFB4') - expect(engine.getCellValue(adr('A2'))).toEqual('FFFFFFFFB4') - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2HEX(2, 0)'], - ['=BIN2HEX(-2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-bin2oct.spec.ts b/test/unit/interpreter/function-bin2oct.spec.ts deleted file mode 100644 index 0bc8e3ed65..0000000000 --- a/test/unit/interpreter/function-bin2oct.spec.ts +++ /dev/null @@ -1,111 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BIN2OCT', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-binary arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT("foo")'], - ['=BIN2OCT(1234)'], - ['=BIN2OCT(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT(1)'], - ['=BIN2OCT(10)'], - ['=BIN2OCT(010)'], - ['=BIN2OCT(101110)'], - ['=BIN2OCT(1000000000)'], - ['=BIN2OCT(1111111111)'], - ['=BIN2OCT(111111111)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('2') - expect(engine.getCellValue(adr('A3'))).toEqual('2') - expect(engine.getCellValue(adr('A4'))).toEqual('56') - expect(engine.getCellValue(adr('A5'))).toEqual('7777777000') - expect(engine.getCellValue(adr('A6'))).toEqual('7777777777') - expect(engine.getCellValue(adr('A7'))).toEqual('777') - }) - - it('should work for binary strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT("1101")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('15') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="1011"'], - ['=BIN2OCT(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('13') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT(10111)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should work only for 10 bits', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT(10101010101010)'], - ['=BIN2OCT(1010101010)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqual('7777777252') - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT(10, 8)'], - ['=BIN2OCT(101, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00000002') - expect(engine.getCellValue(adr('A2'))).toEqual('0005') - }) - - it('second argument should not affect negative results', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT(1110110100, 1)'], - ['=BIN2OCT(1110110100, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('7777777664') - expect(engine.getCellValue(adr('A2'))).toEqual('7777777664') - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=BIN2OCT(2, 0)'], - ['=BIN2OCT(-2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotBinary)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-binom.dist.spec.ts b/test/unit/interpreter/function-binom.dist.spec.ts deleted file mode 100644 index c41ebe8b20..0000000000 --- a/test/unit/interpreter/function-binom.dist.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BINOM.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.DIST(1, 2, 3)'], - ['=BINOM.DIST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.DIST("foo", 2, 3, TRUE())'], - ['=BINOM.DIST(1, "baz", 3, TRUE())'], - ['=BINOM.DIST(1, 2, "baz", TRUE())'], - ['=BINOM.DIST(1, 1, 1, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.DIST(1, 1, 0.1, TRUE())'], - ['=BINOM.DIST(10, 20, 0.7, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0479618973, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.DIST(1, 1, 0.1, FALSE())'], - ['=BINOM.DIST(10, 20, 0.7, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.1) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0308170809000851, 6) - }) - - it('truncation works', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.DIST(1.9, 1.99, 0.1, FALSE())'], - ['=BINOM.DIST(10.5, 20.2, 0.7, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.1) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0308170809000851, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.DIST(-0.00001, 1, 1, FALSE())'], - ['=BINOM.DIST(0.5, -0.01, 1, FALSE())'], - ['=BINOM.DIST(0.5, 0.4, 1, FALSE())'], - ['=BINOM.DIST(1, 1, -0.01, FALSE())'], - ['=BINOM.DIST(1, 1, 1.01, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - //product #2 returns 1 for following test - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WrongOrder)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-binom.inv.spec.ts b/test/unit/interpreter/function-binom.inv.spec.ts deleted file mode 100644 index 6f4420c5e5..0000000000 --- a/test/unit/interpreter/function-binom.inv.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function BINOM.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(1, 2)'], - ['=BINOM.INV(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV("foo", 0.5, 3)'], - ['=BINOM.INV(1, "baz", 3)'], - ['=BINOM.INV(1, 0.5, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(10, 0.5, 0.001)', - '=BINOM.INV(10, 0.5, 0.01)', - '=BINOM.INV(10, 0.5, 0.025)', - '=BINOM.INV(10, 0.5, 0.05)', - '=BINOM.INV(10, 0.5, 0.1)', - '=BINOM.INV(10, 0.5, 0.2)', - '=BINOM.INV(10, 0.5, 0.3)', - '=BINOM.INV(10, 0.5, 0.4)', - '=BINOM.INV(10, 0.5, 0.5)', - '=BINOM.INV(10, 0.5, 0.6)', - '=BINOM.INV(10, 0.5, 0.7)', - '=BINOM.INV(10, 0.5, 0.8)', - '=BINOM.INV(10, 0.5, 0.9)', - '=BINOM.INV(10, 0.5, 0.95)', - '=BINOM.INV(10, 0.5, 0.975)', - '=BINOM.INV(10, 0.5, 0.99)', - '=BINOM.INV(10, 0.5, 0.999)'], - ]) - - expect(engine.getSheetValues(0)).toEqual([[1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9]]) - }) - - it('should work, different p-value', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(10, 0.8, 0.001)', - '=BINOM.INV(10, 0.8, 0.1)', - '=BINOM.INV(10, 0.8, 0.2)', - '=BINOM.INV(10, 0.8, 0.3)', - '=BINOM.INV(10, 0.8, 0.4)', - '=BINOM.INV(10, 0.8, 0.5)', - '=BINOM.INV(10, 0.8, 0.6)', - '=BINOM.INV(10, 0.8, 0.7)', - '=BINOM.INV(10, 0.8, 0.8)', - '=BINOM.INV(10, 0.8, 0.9)', - '=BINOM.INV(10, 0.8, 0.999)'], - ]) - - expect(engine.getSheetValues(0)).toEqual([[4, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10]]) - }) - - it('should work, small number of trials', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(0, 0.8, 0.001)', - '=BINOM.INV(0, 0.8, 0.1)', - '=BINOM.INV(0, 0.8, 0.2)', - '=BINOM.INV(0, 0.8, 0.3)', - '=BINOM.INV(0, 0.8, 0.4)', - '=BINOM.INV(0, 0.8, 0.5)', - '=BINOM.INV(0, 0.8, 0.6)', - '=BINOM.INV(0, 0.8, 0.7)', - '=BINOM.INV(0, 0.8, 0.8)', - '=BINOM.INV(0, 0.8, 0.9)', - '=BINOM.INV(0, 0.8, 0.999)'], - ]) - - expect(engine.getSheetValues(0)).toEqual([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]) - }) - - it('should work, another small number of trials', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(1, 0.8, 0.001)', - '=BINOM.INV(1, 0.8, 0.1)', - '=BINOM.INV(1, 0.8, 0.2)', - '=BINOM.INV(1, 0.8, 0.3)', - '=BINOM.INV(1, 0.8, 0.4)', - '=BINOM.INV(1, 0.8, 0.5)', - '=BINOM.INV(1, 0.8, 0.6)', - '=BINOM.INV(1, 0.8, 0.7)', - '=BINOM.INV(1, 0.8, 0.8)', - '=BINOM.INV(1, 0.8, 0.9)', - '=BINOM.INV(1, 0.8, 0.999)'], - ]) - - //both products #1 and #2 return 1 for '=BINOM.INV(1, 0.8, 0.2)', which is incorrect - expect(engine.getSheetValues(0)).toEqual([[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]]) - }) - - it('should work, large number of trials', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(1000, 0.8, 0.001)', - '=BINOM.INV(1000, 0.8, 0.1)', - '=BINOM.INV(1000, 0.8, 0.2)', - '=BINOM.INV(1000, 0.8, 0.3)', - '=BINOM.INV(1000, 0.8, 0.4)', - '=BINOM.INV(1000, 0.8, 0.5)', - '=BINOM.INV(1000, 0.8, 0.6)', - '=BINOM.INV(1000, 0.8, 0.7)', - '=BINOM.INV(1000, 0.8, 0.8)', - '=BINOM.INV(1000, 0.8, 0.9)', - '=BINOM.INV(1000, 0.8, 0.999)'], - ]) - - expect(engine.getSheetValues(0)).toEqual([[760, 784, 789, 793, 797, 800, 803, 807, 811, 816, 838]]) - }) - - it('truncation works', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(1000.1, 0.8, 0.001)', - '=BINOM.INV(1000.2, 0.8, 0.1)', - '=BINOM.INV(1000.3, 0.8, 0.2)', - '=BINOM.INV(1000.4, 0.8, 0.3)', - '=BINOM.INV(1000.5, 0.8, 0.4)', - '=BINOM.INV(1000.6, 0.8, 0.5)', - '=BINOM.INV(1000.7, 0.8, 0.6)', - '=BINOM.INV(1000.8, 0.8, 0.7)', - '=BINOM.INV(1000.9, 0.8, 0.8)', - '=BINOM.INV(1000.99, 0.8, 0.9)', - '=BINOM.INV(1000.999, 0.8, 0.999)'], - ]) - - expect(engine.getSheetValues(0)).toEqual([[760, 784, 789, 793, 797, 800, 803, 807, 811, 816, 838]]) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=BINOM.INV(0, 0.5, 0.5)'], - ['=BINOM.INV(-0.001, 0.5, 0.5)'], - ['=BINOM.INV(10, 0, 0.5)'], - ['=BINOM.INV(10, 1, 0.5)'], - ['=BINOM.INV(10, -0.001, 0.5)'], - ['=BINOM.INV(10, 1.001, 0.5)'], - ['=BINOM.INV(10, 0.5, 0)'], - ['=BINOM.INV(10, 0.5, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - //product #1 returns 0 for the following test - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - //both products #1 and #2 return NUM for '=BINOM.INV(10, 0, 0.5)', which is incorrect - expect(engine.getCellValue(adr('A3'))).toEqual(0) - //both products #1 and #2 return NUM for '=BINOM.INV(10, 1, 0.5)', which is incorrect - expect(engine.getCellValue(adr('A4'))).toEqual(10) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-bitand.spec.ts b/test/unit/interpreter/function-bitand.spec.ts deleted file mode 100644 index 77daf61d6c..0000000000 --- a/test/unit/interpreter/function-bitand.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BITAND', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITAND(101)'], - ['=BITAND(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITAND(1, "foo")'], - ['=BITAND("bar", 4)'], - ['=BITAND("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITAND(1, -2)'], - ['=BITAND(-1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should not work for non-integers', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITAND(1.2, 2)'], - ['=BITAND(3.14, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITAND(1, 5)'], - ['=BITAND(457, 111)'], - ['=BITAND(BIN2DEC(101), BIN2DEC(1))'], - ['=BITAND(256, 123)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(73) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('should return numeric type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITAND(1, 5)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toEqual(CellValueType.NUMBER) - }) -}) diff --git a/test/unit/interpreter/function-bitlshift.spec.ts b/test/unit/interpreter/function-bitlshift.spec.ts deleted file mode 100644 index f5e29b4860..0000000000 --- a/test/unit/interpreter/function-bitlshift.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BITLSHIFT', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITLSHIFT(101)'], - ['=BITLSHIFT(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITLSHIFT(1, "foo")'], - ['=BITLSHIFT("bar", 4)'], - ['=BITLSHIFT("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for negative value', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITLSHIFT(-5, -2)'], - ['=BITLSHIFT(-1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should work for positive positions', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITLSHIFT(0, 0)'], - ['=BITLSHIFT(0, 2)'], - ['=BITLSHIFT(2, 2)'], - ['=BITLSHIFT(123, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(8) - expect(engine.getCellValue(adr('A4'))).toEqual(984) - }) - - it('should work for negative positions', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITLSHIFT(0, -2)', '=BITRSHIFT(0, 2)'], - ['=BITLSHIFT(2, -5)', '=BITRSHIFT(2, 5)'], - ['=BITLSHIFT(123, -2)', '=BITRSHIFT(123, 2)'], - ['=BITLSHIFT(4786, -3)', '=BITRSHIFT(4786, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(30) - expect(engine.getCellValue(adr('A4'))).toEqual(598) - - expect(engine.getCellValue(adr('A1'))).toEqual(engine.getCellValue(adr('B1'))) - expect(engine.getCellValue(adr('A2'))).toEqual(engine.getCellValue(adr('B2'))) - expect(engine.getCellValue(adr('A3'))).toEqual(engine.getCellValue(adr('B3'))) - expect(engine.getCellValue(adr('A4'))).toEqual(engine.getCellValue(adr('B4'))) - }) - - it('works only for 48 bit results', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITLSHIFT(2, 46)'], - ['=BITLSHIFT(2, 47)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(140737488355328, -4) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.BitshiftLong)) - }) - - it('works only for positions from -53 to 53', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITLSHIFT(0, -54)'], - ['=BITLSHIFT(0, -53)'], - ['=BITLSHIFT(0, 53)'], - ['=BITLSHIFT(0, 54)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-bitor.spec.ts b/test/unit/interpreter/function-bitor.spec.ts deleted file mode 100644 index d8b5cfb770..0000000000 --- a/test/unit/interpreter/function-bitor.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BITOR', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITOR(101)'], - ['=BITOR(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITOR(1, "foo")'], - ['=BITOR("bar", 4)'], - ['=BITOR("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITOR(1, -2)'], - ['=BITOR(-1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should not work for non-integers', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITOR(1.2, 2)'], - ['=BITOR(3.14, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITOR(1, 5)'], - ['=BITOR(457, 111)'], - ['=BITOR(BIN2DEC(101), BIN2DEC(1))'], - ['=BITOR(256, 123)'], - ['=BITOR(0, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - expect(engine.getCellValue(adr('A2'))).toEqual(495) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - expect(engine.getCellValue(adr('A4'))).toEqual(379) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - }) - - it('should return numeric type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITOR(1, 5)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toEqual(CellValueType.NUMBER) - }) -}) diff --git a/test/unit/interpreter/function-bitrshift.spec.ts b/test/unit/interpreter/function-bitrshift.spec.ts deleted file mode 100644 index 77602fc6fb..0000000000 --- a/test/unit/interpreter/function-bitrshift.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BITRSHIFT', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITRSHIFT(101)'], - ['=BITRSHIFT(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITRSHIFT(1, "foo")'], - ['=BITRSHIFT("bar", 4)'], - ['=BITRSHIFT("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for negative value', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITRSHIFT(-5, -2)'], - ['=BITRSHIFT(-1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should work for positive positions', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITRSHIFT(0, 0)'], - ['=BITRSHIFT(0, 2)'], - ['=BITRSHIFT(50, 2)'], - ['=BITRSHIFT(123, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(12) - expect(engine.getCellValue(adr('A4'))).toEqual(15) - }) - - it('should work for negative positions', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITRSHIFT(0, -2)', '=BITLSHIFT(0, 2)'], - ['=BITRSHIFT(2, -5)', '=BITLSHIFT(2, 5)'], - ['=BITRSHIFT(123, -2)', '=BITLSHIFT(123, 2)'], - ['=BITRSHIFT(4786, -3)', '=BITLSHIFT(4786, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(64) - expect(engine.getCellValue(adr('A3'))).toEqual(492) - expect(engine.getCellValue(adr('A4'))).toEqual(38288) - - expect(engine.getCellValue(adr('A1'))).toEqual(engine.getCellValue(adr('B1'))) - expect(engine.getCellValue(adr('A2'))).toEqual(engine.getCellValue(adr('B2'))) - expect(engine.getCellValue(adr('A3'))).toEqual(engine.getCellValue(adr('B3'))) - expect(engine.getCellValue(adr('A4'))).toEqual(engine.getCellValue(adr('B4'))) - }) - - it('works only for 48 bit results', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITRSHIFT(2, -46)'], - ['=BITRSHIFT(2, -47)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(140737488355328, -4) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.BitshiftLong)) - }) - - it('works only for positions from -53 to 53', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITRSHIFT(0, -54)'], - ['=BITRSHIFT(0, -53)'], - ['=BITRSHIFT(0, 53)'], - ['=BITRSHIFT(0, 54)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-bitxor.spec.ts b/test/unit/interpreter/function-bitxor.spec.ts deleted file mode 100644 index 522e7fc203..0000000000 --- a/test/unit/interpreter/function-bitxor.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function BITXOR', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITXOR(101)'], - ['=BITXOR(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITXOR(1, "foo")'], - ['=BITXOR("bar", 4)'], - ['=BITXOR("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITXOR(1, -2)'], - ['=BITXOR(-1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should not work for non-integers', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITXOR(1.2, 2)'], - ['=BITXOR(3.14, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITXOR(1, 5)'], - ['=BITXOR(457, 111)'], - ['=BITXOR(BIN2DEC(101), BIN2DEC(1))'], - ['=BITXOR(256, 123)'], - ['=BITXOR(0, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - expect(engine.getCellValue(adr('A2'))).toEqual(422) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(379) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - }) - - it('should return numeric type', () => { - const engine = HyperFormula.buildFromArray([ - ['=BITXOR(1, 5)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toEqual(CellValueType.NUMBER) - }) -}) diff --git a/test/unit/interpreter/function-ceiling.math.spec.ts b/test/unit/interpreter/function-ceiling.math.spec.ts deleted file mode 100644 index 28ed71e984..0000000000 --- a/test/unit/interpreter/function-ceiling.math.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CEILING.MATH', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.MATH()'], - ['=CEILING.MATH(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.MATH("foo")'], - ['=CEILING.MATH(1, "bar")'], - ['=CEILING.MATH(1, 2, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.MATH(4.43, 0.3)'], - ['=CEILING.MATH(4.43, 0.6)'], - ['=CEILING.MATH(4.43, 2)'], - ['=CEILING.MATH(4.43)'], - ['=CEILING.MATH(-4.43)'], - ['=CEILING.MATH(-3.14, -1.8)'], - ['=CEILING.MATH(-3.14, 0)'], - ['=CEILING.MATH(3.14, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4.5) - expect(engine.getCellValue(adr('A2'))).toEqual(4.8) - expect(engine.getCellValue(adr('A3'))).toEqual(6) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - expect(engine.getCellValue(adr('A5'))).toEqual(-4) - expect(engine.getCellValue(adr('A6'))).toEqual(-1.8) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - expect(engine.getCellValue(adr('A8'))).toEqual(0) - }) - - it('should work with mode for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.MATH(-11, -2)'], - ['=CEILING.MATH(-11, -2, 0)'], - ['=CEILING.MATH(-11, -2, 1)'], - ['=CEILING.MATH(-11, 0, 1)'], - ['=CEILING.MATH(-11, 0, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-10) - expect(engine.getCellValue(adr('A2'))).toEqual(-10) - expect(engine.getCellValue(adr('A3'))).toEqual(-12) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - }) - - it('negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.MATH(11, 2, 0)'], - ['=CEILING.MATH(-11, 2, 0)'], - ['=CEILING.MATH(11, -2, 0)'], - ['=CEILING.MATH(-11, -2, 0)'], - ['=CEILING.MATH(11, 2, 1)'], - ['=CEILING.MATH(-11, 2, 1)'], - ['=CEILING.MATH(11, -2, 1)'], - ['=CEILING.MATH(-11, -2, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('A2'))).toEqual(-10) - expect(engine.getCellValue(adr('A3'))).toEqual(12) - expect(engine.getCellValue(adr('A4'))).toEqual(-10) - expect(engine.getCellValue(adr('A5'))).toEqual(12) - expect(engine.getCellValue(adr('A6'))).toEqual(-12) - expect(engine.getCellValue(adr('A7'))).toEqual(12) - expect(engine.getCellValue(adr('A8'))).toEqual(-12) - }) -}) diff --git a/test/unit/interpreter/function-ceiling.precise.spec.ts b/test/unit/interpreter/function-ceiling.precise.spec.ts deleted file mode 100644 index 21fa16fe0b..0000000000 --- a/test/unit/interpreter/function-ceiling.precise.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CEILING.PRECISE', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.PRECISE()'], - ['=CEILING.PRECISE(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.PRECISE(1, "bar")'], - ['=CEILING.PRECISE("bar", 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.PRECISE(4.43, 0.3)'], - ['=CEILING.PRECISE(4.43, 0.6)'], - ['=CEILING.PRECISE(4.43, 2)'], - ['=CEILING.PRECISE(-3.14, -1.8)'], - ['=CEILING.PRECISE(-3.14, 0)'], - ['=CEILING.PRECISE(3.14, 0)'], - ['=CEILING.PRECISE(3.14)'], - ['=CEILING.PRECISE(-3.14)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4.5) - expect(engine.getCellValue(adr('A2'))).toEqual(4.8) - expect(engine.getCellValue(adr('A3'))).toEqual(6) - expect(engine.getCellValue(adr('A4'))).toEqual(-1.8) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(0) - expect(engine.getCellValue(adr('A7'))).toEqual(4) - expect(engine.getCellValue(adr('A8'))).toEqual(-3) - }) - - it('negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING.PRECISE(11, 2)'], - ['=CEILING.PRECISE(-11, 2)'], - ['=CEILING.PRECISE(11, -2)'], - ['=CEILING.PRECISE(-11, -2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('A2'))).toEqual(-10) - expect(engine.getCellValue(adr('A3'))).toEqual(12) - expect(engine.getCellValue(adr('A4'))).toEqual(-10) - }) -}) diff --git a/test/unit/interpreter/function-ceiling.spec.ts b/test/unit/interpreter/function-ceiling.spec.ts deleted file mode 100644 index b0e9ea174a..0000000000 --- a/test/unit/interpreter/function-ceiling.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CEILING', () => { - /*Inconsistent with ODFF standard.*/ - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING(1)'], - ['=CEILING(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING(1, "bar")'], - ['=CEILING("bar", 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING(4.43, 0.3)'], - ['=CEILING(4.43, 0.6)'], - ['=CEILING(4.43, 2)'], - ['=CEILING(-3.14, -1.8)'], - ['=CEILING(-3.14, 0)'], - ['=CEILING(3.14, 0)'], - ['=CEILING(0, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4.5) - expect(engine.getCellValue(adr('A2'))).toEqual(4.8) - expect(engine.getCellValue(adr('A3'))).toEqual(6) - expect(engine.getCellValue(adr('A4'))).toEqual(-3.6) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - }) - - /*Inconsistent with ODFF standard.*/ - it('negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=CEILING(11, 2)'], - ['=CEILING(-11, 2)'], - ['=CEILING(11, -2)'], - ['=CEILING(-11, -2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('A2'))).toEqual(-10) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.DistinctSigns)) - expect(engine.getCellValue(adr('A4'))).toEqual(-12) - }) -}) diff --git a/test/unit/interpreter/function-char.spec.ts b/test/unit/interpreter/function-char.spec.ts deleted file mode 100644 index e947f18f6d..0000000000 --- a/test/unit/interpreter/function-char.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CHAR', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHAR()'], - ['=CHAR(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHAR("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHAR(1)'], - ['=CHAR(33)'], - ['=CHAR(65)'], - ['=CHAR(90)'], - ['=CHAR(209)'], - ['=CHAR(255)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('!') - expect(engine.getCellValue(adr('A3'))).toEqual('A') - expect(engine.getCellValue(adr('A4'))).toEqual('Z') - expect(engine.getCellValue(adr('A5'))).toEqual('Ñ') - expect(engine.getCellValue(adr('A6'))).toEqual('ÿ') - }) - - it('should round down floats', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHAR(42)'], - ['=CHAR(42.2)'], - ['=CHAR(42.8)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('*') - expect(engine.getCellValue(adr('A2'))).toEqual('*') - expect(engine.getCellValue(adr('A3'))).toEqual('*') - }) - - it('should work only for values from 1 to 255 truncating decimal part', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHAR(0)'], - ['=CHAR(1)'], - ['=CHAR(255)'], - ['=CHAR(256)'], - ['=CHAR(0.5)'], - ['=CHAR(255.5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds)) - expect(engine.getCellValue(adr('A2'))).toEqual('') - expect(engine.getCellValue(adr('A3'))).toEqual('ÿ') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds)) - expect(engine.getCellValue(adr('A6'))).toEqual('ÿ') - }) -}) diff --git a/test/unit/interpreter/function-chisq.dist.rt.spec.ts b/test/unit/interpreter/function-chisq.dist.rt.spec.ts deleted file mode 100644 index a781782f83..0000000000 --- a/test/unit/interpreter/function-chisq.dist.rt.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CHISQ.DIST.RT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST.RT(1)'], - ['=CHISQ.DIST.RT(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST.RT("foo", 2)'], - ['=CHISQ.DIST.RT(1, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST.RT(1, 1)'], - ['=CHISQ.DIST.RT(3, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.317310507862944, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.22313016014843, 6) - }) - - it('truncates second arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST.RT(1, 1.9)'], - ['=CHISQ.DIST.RT(3, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.317310507862944, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.22313016014843, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST.RT(10, 0.999)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-chisq.dist.spec.ts b/test/unit/interpreter/function-chisq.dist.spec.ts deleted file mode 100644 index 12fe8990f9..0000000000 --- a/test/unit/interpreter/function-chisq.dist.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CHISQ.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST(1, 2)'], - ['=CHISQ.DIST(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST("foo", 2, TRUE())'], - ['=CHISQ.DIST(1, "baz", TRUE())'], - ['=CHISQ.DIST(1, 2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST(1, 1, TRUE())'], - ['=CHISQ.DIST(3, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.682689492137056, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.77686983985157, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST(1, 1, FALSE())'], - ['=CHISQ.DIST(3, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.241970724519133, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.111565080074215, 6) - }) - - it('truncates second arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST(1, 1.9, FALSE())'], - ['=CHISQ.DIST(3, 2.9, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.241970724519133, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.111565080074215, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.DIST(10, 0.999, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-chisq.inv.rt.spec.ts b/test/unit/interpreter/function-chisq.inv.rt.spec.ts deleted file mode 100644 index f320fa1f53..0000000000 --- a/test/unit/interpreter/function-chisq.inv.rt.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CHISQ.INV.RT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV.RT(1)'], - ['=CHISQ.INV.RT(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV.RT("foo", 2)'], - ['=CHISQ.INV.RT(1, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV.RT(0.1, 1)'], - ['=CHISQ.INV.RT(0.9, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.70554345409603, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.210721031315653, 6) - }) - - it('truncates second arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV.RT(0.1, 1.9)'], - ['=CHISQ.INV.RT(0.9, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.70554345409603, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.210721031315653, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV.RT(0.5, 0.999)'], - ['=CHISQ.INV.RT(-0.0001, 2)'], - ['=CHISQ.INV.RT(1.0001, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-chisq.inv.spec.ts b/test/unit/interpreter/function-chisq.inv.spec.ts deleted file mode 100644 index 0fdfccb577..0000000000 --- a/test/unit/interpreter/function-chisq.inv.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CHISQ.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV(1)'], - ['=CHISQ.INV(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV("foo", 2)'], - ['=CHISQ.INV(1, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV(0.1, 1)'], - ['=CHISQ.INV(0.9, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0157907740934326, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(4.60517018598809, 6) - }) - - it('truncates second arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV(0.1, 1.9)'], - ['=CHISQ.INV(0.9, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0157907740934326, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(4.60517018598809, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.INV(0.5, 0.999)'], - ['=CHISQ.INV(-0.0001, 2)'], - ['=CHISQ.INV(1.0001, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-chisq.test.spec.ts b/test/unit/interpreter/function-chisq.test.spec.ts deleted file mode 100644 index fc41402b63..0000000000 --- a/test/unit/interpreter/function-chisq.test.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('CHISQ.TEST', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.TEST(1)'], - ['=CHISQ.TEST(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10], - [2, 5], - ['=CHISQ.TEST(A1:A2, B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.001652787719, 6) - }) - - it('works for larger ranges', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, 8], - ['=CHISQ.TEST(A1:C2, D1:F2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.00000054330486, 9) - }) - - /** - * product #2 accepts this as a valid input - */ - it('validates dimensions', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, 8], - ['=CHISQ.TEST(A1:C2, A1:F1)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('validates values #1', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, 0], - ['=CHISQ.TEST(A1:C2, D1:F2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('accepts negative values', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, -1], - ['=CHISQ.TEST(A1:C2, D1:F2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.0000858340104264999, 9) - }) - - it('but checks intermediate values for negatives', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, -0.001], - ['=CHISQ.TEST(A1:C2, D1:F2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, null, 1, 4, 8], - ['=CHISQ.TEST(A1:C2, D1:F2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.00001161637011, 9) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=NA()', '50'], - ['3', '30'], - ['=CHISQ.TEST(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHISQ.TEST(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - }) -}) diff --git a/test/unit/interpreter/function-choose.spec.ts b/test/unit/interpreter/function-choose.spec.ts deleted file mode 100644 index 931e6796c7..0000000000 --- a/test/unit/interpreter/function-choose.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - CHOOSE function', () => { - it('Should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(0)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('Should work with more arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(1, 2, 3)', '=CHOOSE(3, 2, 3, 4)', '=CHOOSE(2, 2, 3, 4, 5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('C1'))).toEqual(3) - }) - - it('should preserve types', () => { - const engine = HyperFormula.buildFromArray([['=CHOOSE(1, B1, 3)', '1%']]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('preserves types of second arg', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR(NA(), B1)', '1%']]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('Should fail when wrong first argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(1.5, 2, 3)', '=CHOOSE(0, 2, 3, 4)', '=CHOOSE(5, 2, 3, 4, 5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.Selector)) - }) - - it('Coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(TRUE(), 2, 3)', '=CHOOSE("31/12/1899", 2, 3, 4)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - }) - - it('Should fail with error in first argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(1/0, 3, 4, 5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - it('Should not fail with error in other arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(4, 1/0, 3, 4, 5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - it('Should pass errors as normal values', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(4, 2, 3, 4, 1/0)', '=CHOOSE(1, 2, 3, 4, COS(1, 1), 5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - }) - it('Should fail with range', () => { - const engine = HyperFormula.buildFromArray([ - ['=CHOOSE(1, 2, A2:A3, 4, 5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-clean.spec.ts b/test/unit/interpreter/function-clean.spec.ts deleted file mode 100644 index 06e4d6bcdc..0000000000 --- a/test/unit/interpreter/function-clean.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CLEAN', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=CLEAN()'], - ['=CLEAN("foo", "bar")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CLEAN("foo\u0000")'], - ['=CLEAN("foo\u0020")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('A2'))).toEqual('foo\u0020') - }) - - it('should clean all non-printable ASCII characters', () => { - const str = Array.from(Array(32).keys()).map(code => String.fromCharCode(code)).join('') - - const engine = HyperFormula.buildFromArray([ - [str, '=LEN(A1)', '=CLEAN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(32) - expect(engine.getCellValue(adr('C1'))).toEqual('') - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=CLEAN(1)'], - ['=CLEAN(5+5)'], - ['=CLEAN(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('10') - expect(engine.getCellValue(adr('A3'))).toEqual('TRUE') - }) -}) diff --git a/test/unit/interpreter/function-code.spec.ts b/test/unit/interpreter/function-code.spec.ts deleted file mode 100644 index 53ce41fc9d..0000000000 --- a/test/unit/interpreter/function-code.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {CellValueType, ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CODE', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CODE()'], - ['=CODE("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for empty strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=CODE("")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EmptyString)) - }) - - it('should work for single chars', () => { - const engine = HyperFormula.buildFromArray([ - ['=CODE("")'], - ['=CODE("!")'], - ['=CODE("A")'], - ['=CODE("Z")'], - ['=CODE("Ñ")'], - ['=CODE("ÿ")'], - ['=CODE(TRUE())'], - ['=CODE("€")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(33) - expect(engine.getCellValue(adr('A3'))).toEqual(65) - expect(engine.getCellValue(adr('A4'))).toEqual(90) - expect(engine.getCellValue(adr('A5'))).toEqual(209) - expect(engine.getCellValue(adr('A6'))).toEqual(255) - expect(engine.getCellValue(adr('A7'))).toEqual(84) - expect(engine.getCellValue(adr('A8'))).toEqual(8364) - }) - - it('should return code of first character', () => { - const engine = HyperFormula.buildFromArray([ - ['=CODE("Abar")'], - ['=CODE("Ñbaz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(65) - expect(engine.getCellValue(adr('A2'))).toEqual(209) - }) - - it('should return number', () => { - const engine = HyperFormula.buildFromArray([ - ['=CODE("foo")'] - ]) - - expect(engine.getCellValueType(adr('A1'))).toEqual(CellValueType.NUMBER) - }) - - it('should be identity when composed with CHAR', () => { - const engine = HyperFormula.buildFromArray([ - ['=CODE(CHAR(1))'], - ['=CODE(CHAR(128))'], - ['=CODE(CHAR(255))'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(128) - expect(engine.getCellValue(adr('A3'))).toEqual(255) - }) -}) diff --git a/test/unit/interpreter/function-column.spec.ts b/test/unit/interpreter/function-column.spec.ts deleted file mode 100644 index a207b96da9..0000000000 --- a/test/unit/interpreter/function-column.spec.ts +++ /dev/null @@ -1,117 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COLUMN', () => { - it('should take one or zero arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN(B1, B2)'], - ['=COLUMN(B1, B2, B3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should take only reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN(42)'], - ['=COLUMN("foo")'], - ['=COLUMN(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN(1/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return row of a reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN(A2)'], - ['=COLUMN(G7)'], - ['=COLUMN($E5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(7) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - }) - - it('should work for itself', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN(A1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should return row of a cell in which formula is', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=COLUMN()'], - ['=COLUMN()'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('should return row of range start', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN(C1:D1)'], - ['=COLUMN(A1:B1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('should be dependent on sheet structure changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=COLUMN(A1)'] - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - - engine.addColumns(0, [0, 1]) - - expect(engine.getCellValue(adr('B2'))).toEqual(2) - }) - - it('should collect dependencies of inner function and return argument type error', () => { - const engine = HyperFormula.buildFromArray([ - ['=SIN(1)'], - ['=COLUMN(SUM(A1,A3))'], - ['=SIN(1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - }) - - it('should propagate error of inner function', () => { - const engine = HyperFormula.buildFromArray([ - ['=1/0'], - ['=COLUMN(SUM(A1, A3))'], - ['=1/0'] - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return #CYCLE! when cyclic reference occurs not directly in COLUMN', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN(SUM(A1))'], - ['=COLUMN(A1+A2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) -}) diff --git a/test/unit/interpreter/function-columns.spec.ts b/test/unit/interpreter/function-columns.spec.ts deleted file mode 100644 index 96e9388c0e..0000000000 --- a/test/unit/interpreter/function-columns.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COLUMNS', () => { - it('accepts exactly one argument', () => { - const engine = HyperFormula.buildFromArray([['=COLUMNS()', '=COLUMNS(A1:B1, A2:B2)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for range', () => { - const engine = HyperFormula.buildFromArray([['=COLUMNS(A1:C2)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works for column range', () => { - const engine = HyperFormula.buildFromArray([['=COLUMNS(A:C)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works for row range', () => { - const engine = HyperFormula.buildFromArray([['=COLUMNS(1:2)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(engine.getConfig().maxColumns) - }) - - it('works for array', () => { - const engine = HyperFormula.buildFromArray([['=COLUMNS({1,2,3})']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works with cell reference', () => { - const engine = HyperFormula.buildFromArray([['=COLUMNS(A1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('error when nested cycle', () => { - const engine = HyperFormula.buildFromArray([['=COLUMNS(A1+1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) - - it('propagates only direct errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=COLUMNS(4/0)'], - ['=COLUMNS(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('works with formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['1', '1'], - ['=COLUMNS(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('should work when adding column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['=COLUMNS(A1:B1)'] - ]) - - engine.addColumns(0, [1, 1]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) -}) diff --git a/test/unit/interpreter/function-combin.spec.ts b/test/unit/interpreter/function-combin.spec.ts deleted file mode 100644 index 92e02f439d..0000000000 --- a/test/unit/interpreter/function-combin.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COMBIN', () => { - it('checks number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBIN(1)', '=COMBIN(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBIN(0,0)'], - ['=COMBIN(1,0)'], - ['=COMBIN(4,2)'], - ['=COMBIN(9,6)'], - ['=COMBIN(20,10)'], - ['=COMBIN(30,10)'], - ['=COMBIN(40,10)'], - ['=COMBIN(100,99)'], - ['=COMBIN(100,8)'], - ['=COMBIN(1029,512)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(1) - expect(engine.getCellValue(adr('A3'))).toBe(6) - expect(engine.getCellValue(adr('A4'))).toBe(84) - expect(engine.getCellValue(adr('A5'))).toBe(184756) - expect(engine.getCellValue(adr('A6'))).toBe(30045015) - expect(engine.getCellValue(adr('A7'))).toBe(847660528) - expect(engine.getCellValue(adr('A8'))).toBe(100) - expect(engine.getCellValue(adr('A9'))).toBe(186087894300) - expect(engine.getCellValue(adr('A10')) as number / 1.41325918108873e+308).toBeCloseTo(1, 6) - }) - - it('truncates argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBIN(9.9,6.6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(84) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBIN(1.1, 1.2)'], - ['=COMBIN(1, 2)'], - ['=COMBIN(2, -1)'], - ['=COMBIN(-1, -1)'], - ['=COMBIN(1030, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WrongOrder)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WrongOrder)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - //inconsistency with product #2 - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('uses coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBIN(TRUE(),"0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBIN(NA(), NA())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-combina.spec.ts b/test/unit/interpreter/function-combina.spec.ts deleted file mode 100644 index 9522e55b9b..0000000000 --- a/test/unit/interpreter/function-combina.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COMBINA', () => { - it('checks number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBINA(1)', '=COMBINA(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBINA(0,0)'], - ['=COMBINA(1,0)'], - ['=COMBINA(2,2)'], - ['=COMBINA(0,2)'], - ['=COMBINA(10,10)'], - ['=COMBINA(20,10)'], - ['=COMBINA(30,10)'], - ['=COMBINA(100,500)'], - ['=COMBINA(100,8)'], - ['=COMBINA(518,512)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(1) - expect(engine.getCellValue(adr('A3'))).toBe(3) - expect(engine.getCellValue(adr('A4'))).toBe(1) - expect(engine.getCellValue(adr('A5'))).toBe(92378) - expect(engine.getCellValue(adr('A6'))).toBe(20030010) - expect(engine.getCellValue(adr('A7'))).toBe(635745396) - expect(engine.getCellValue(adr('A8')) as number / 1.8523520317769801e+115).toBeCloseTo(1, 6) - expect(engine.getCellValue(adr('A9'))).toBeCloseTo(325949656825, -2) - expect(engine.getCellValue(adr('A10')) as number / 1.41325918108873e+308).toBeCloseTo(1, 6) - }) - - it('truncates argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBINA(9.9,6.6)'], - ['=COMBINA(518, 512.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3003) - expect(engine.getCellValue(adr('A2')) as number / 1.41325918108873e+308).toBeCloseTo(1) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBINA(2, -1)'], - ['=COMBINA(-1, 2)'], - ['=COMBINA(1031, 0)'], - ['=COMBINA(518, 513)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('uses coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBINA(TRUE(),"0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMBINA(NA(), NA())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-complex.spec.ts b/test/unit/interpreter/function-complex.spec.ts deleted file mode 100644 index 12dd20770d..0000000000 --- a/test/unit/interpreter/function-complex.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COMPLEX', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMPLEX(1)'], - ['=COMPLEX(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMPLEX("foo", 2)'], - ['=COMPLEX(1, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMPLEX(0, 0)'], - ['=COMPLEX(0, 1)'], - ['=COMPLEX(0, -1)'], - ['=COMPLEX(0, 2)'], - ['=COMPLEX(0, -2)'], - ['=COMPLEX(1, 0)'], - ['=COMPLEX(1, 1)'], - ['=COMPLEX(1, -1)'], - ['=COMPLEX(1, 2)'], - ['=COMPLEX(1, -2)'], - ['=COMPLEX(-1, 0)'], - ['=COMPLEX(-1, 1)'], - ['=COMPLEX(-1, -1)'], - ['=COMPLEX(-1, 2)'], - ['=COMPLEX(-1, -2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0') - expect(engine.getCellValue(adr('A2'))).toEqual('i') - expect(engine.getCellValue(adr('A3'))).toEqual('-i') - expect(engine.getCellValue(adr('A4'))).toEqual('2i') - expect(engine.getCellValue(adr('A5'))).toEqual('-2i') - expect(engine.getCellValue(adr('A6'))).toEqual('1') - expect(engine.getCellValue(adr('A7'))).toEqual('1+i') - expect(engine.getCellValue(adr('A8'))).toEqual('1-i') - expect(engine.getCellValue(adr('A9'))).toEqual('1+2i') - expect(engine.getCellValue(adr('A10'))).toEqual('1-2i') - expect(engine.getCellValue(adr('A11'))).toEqual('-1') - expect(engine.getCellValue(adr('A12'))).toEqual('-1+i') - expect(engine.getCellValue(adr('A13'))).toEqual('-1-i') - expect(engine.getCellValue(adr('A14'))).toEqual('-1+2i') - expect(engine.getCellValue(adr('A15'))).toEqual('-1-2i') - }) - - it('should work with third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=COMPLEX(1, 1, "i")'], - ['=COMPLEX(1, 1, "j")'], - ['=COMPLEX(1, 1, "k")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1+i') - expect(engine.getCellValue(adr('A2'))).toEqual('1+j') - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ShouldBeIorJ)) - }) -}) diff --git a/test/unit/interpreter/function-concatenate.spec.ts b/test/unit/interpreter/function-concatenate.spec.ts deleted file mode 100644 index fbf8e9a68e..0000000000 --- a/test/unit/interpreter/function-concatenate.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function CONCATENATE', () => { - it('validate arguments', () => { - const engine = HyperFormula.buildFromArray([['=CONCATENATE()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([['John', 'Smith', '=CONCATENATE(A1, B1)']]) - - expect(engine.getCellValue(adr('C1'))).toEqual('JohnSmith') - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0', '=FOOBAR()'], - ['=CONCATENATE(4/0)'], - ['=CONCATENATE(A1)'], - ['=CONCATENATE(A1,B1)'], - ['=CONCATENATE(A1:B1)'], - ['=CONCATENATE(C1,B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('empty value is empty string', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', '', 'bar', '=CONCATENATE(A1, B1, C1)'], - ]) - - expect(engine.getCellValue(adr('D1'))).toEqual('foobar') - }) - - it('supports range values', () => { - const engine = HyperFormula.buildFromArray([ - ['Topleft', 'Topright'], - ['Bottomleft', 'Bottomright'], - ['=CONCATENATE(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('TopleftToprightBottomleftBottomright') - }) - - it('coerce to strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', '42', '=CONCATENATE(A1:B1)'], - ['=TRUE()', '=42%', '=CONCATENATE(A2:B2)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual('TRUE42') - expect(engine.getCellValue(adr('C2'))).toEqual('TRUE0.42') - }) -}) diff --git a/test/unit/interpreter/function-confidence.norm.spec.ts b/test/unit/interpreter/function-confidence.norm.spec.ts deleted file mode 100644 index 36a90c082e..0000000000 --- a/test/unit/interpreter/function-confidence.norm.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CONFIDENCE.NORM', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.NORM(1, 2)'], - ['=CONFIDENCE.NORM(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.NORM("foo", 2, 3)'], - ['=CONFIDENCE.NORM(0.5, "baz", 3)'], - ['=CONFIDENCE.NORM(0.5, 2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.NORM(0.1, 1, 1)'], - ['=CONFIDENCE.NORM(0.9, 10, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.64485362695147, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.561974627424251, 6) - }) - - it('should truncate third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.NORM(0.1, 1, 1.9)'], - ['=CONFIDENCE.NORM(0.9, 10, 5.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.64485362695147, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.561974627424251, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.NORM(0.01, 0.01, 1)'], - ['=CONFIDENCE.NORM(0, 0.01, 1)'], - ['=CONFIDENCE.NORM(0.01, 0, 1)'], - ['=CONFIDENCE.NORM(0.01, 0.1, 0.99)'], - ['=CONFIDENCE.NORM(0.99, 0.01, 1)'], - ['=CONFIDENCE.NORM(1, 0.01, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0257582930354889, 6) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(0.000125334695080692, 6) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-confidence.t.spec.ts b/test/unit/interpreter/function-confidence.t.spec.ts deleted file mode 100644 index 0cc83cac2a..0000000000 --- a/test/unit/interpreter/function-confidence.t.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CONFIDENCE.T', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.T(1, 2)'], - ['=CONFIDENCE.T(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.T("foo", 2, 3)'], - ['=CONFIDENCE.T(0.5, "baz", 3)'], - ['=CONFIDENCE.T(0.5, 2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.T(0.1, 1, 2)'], - ['=CONFIDENCE.T(0.9, 10, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(4.46449651075278, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.59850759663214, 6) - }) - - it('should truncate third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.T(0.1, 1, 2.9)'], - ['=CONFIDENCE.T(0.9, 10, 5.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(4.46449651075278, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.59850759663214, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=CONFIDENCE.T(0.01, 0.01, 2)'], - ['=CONFIDENCE.T(0, 0.01, 2)'], - ['=CONFIDENCE.T(0.01, 0, 2)'], - ['=CONFIDENCE.T(0.01, 0.1, 1.99)'], - ['=CONFIDENCE.T(0.99, 0.01, 2)'], - ['=CONFIDENCE.T(1, 0.01, 2)'], - ['=CONFIDENCE.T(0.01, 0.1, 0.99)'], - ['=CONFIDENCE.T(0.01, 0.1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.450121133444994, 6) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(0.000111081209667629, 6) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-correl.spec.ts b/test/unit/interpreter/function-correl.spec.ts deleted file mode 100644 index b47b683256..0000000000 --- a/test/unit/interpreter/function-correl.spec.ts +++ /dev/null @@ -1,92 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('CORREL', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CORREL(B1:B5)'], - ['=CORREL(B1:B5, C1:C5, D1:D5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('ranges need to have same amount of elements', () => { - const engine = HyperFormula.buildFromArray([ - ['=CORREL(B1:B5, C1:C6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('works (simple)', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['2', '20'], - ['=CORREL(A1:A2, B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBe(1) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '4'], - ['5', '3'], - ['7', '6'], - ['1', '1'], - ['8', '5'], - ['=CORREL(A1:A5, B1:B5)'] - ]) - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(0.7927032095) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=CORREL(A1:A1, B1:B1)'], - ['=CORREL(42, 43)'], - ['=CORREL("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['="2"', '50'], - ['3', '30'], - ['=CORREL(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=CORREL(MMULT(A1:B2, A1:B2), MMULT(B1:C2, B1:C2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.999248091927219, 6) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=4/0', '50'], - ['3', '30'], - ['=CORREL(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-cos.spec.ts b/test/unit/interpreter/function-cos.spec.ts deleted file mode 100644 index b199115d06..0000000000 --- a/test/unit/interpreter/function-cos.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COS', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=COS(0)', '=COS(7)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.753902254343305) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=COS("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=COS()', '=COS(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=COS(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.54030230586814) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=COS(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-cosh.spec.ts b/test/unit/interpreter/function-cosh.spec.ts deleted file mode 100644 index 17c492ea80..0000000000 --- a/test/unit/interpreter/function-cosh.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COSH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=COSH(0)', '=COSH(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.54308063481524) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=COSH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=COSH()', '=COSH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=COSH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.54308063481524) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=COSH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-cot.spec.ts b/test/unit/interpreter/function-cot.spec.ts deleted file mode 100644 index d2d46bd396..0000000000 --- a/test/unit/interpreter/function-cot.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COT', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=COT(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.642092615934331) - }) - - it('DIV/0 for zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=COT(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=COT("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=COT()', '=COT(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=COT(A1)'], - ['', '=COT(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.642092615934331) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=COT(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-coth.spec.ts b/test/unit/interpreter/function-coth.spec.ts deleted file mode 100644 index a37a314308..0000000000 --- a/test/unit/interpreter/function-coth.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COTH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=COTH(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.31303528549933) - }) - - it('DIV/0 for zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=COTH(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=COTH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=COTH()', '=COTH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=COTH(A1)'], - ['', '=COTH(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-1.31303528549933) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=COTH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-count.spec.ts b/test/unit/interpreter/function-count.spec.ts deleted file mode 100644 index 97f84cc680..0000000000 --- a/test/unit/interpreter/function-count.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('COUNT', () => { - it('COUNT with empty args', () => { - const engine = HyperFormula.buildFromArray([['=COUNT()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('COUNT with args', () => { - const engine = HyperFormula.buildFromArray([['=COUNT(1, B1)', '3.14']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('COUNT with range', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=COUNT(A1:A3)']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('COUNT ignores all nonnumeric arguments', () => { - const engine = HyperFormula.buildFromArray([['foo'], [null], ['=TRUE()'], ['=COUNT(A1:A3)']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=COUNT(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(4) - }) - - it('error in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['', ''], - ['=COUNT(MMULT(A1:B3, A1:B3))'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('doesnt propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=COUNT(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('should work with explicit error in arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNT(NA())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('should work for empty arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNT(1,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/function-counta.spec.ts b/test/unit/interpreter/function-counta.spec.ts deleted file mode 100644 index 0b55282a1e..0000000000 --- a/test/unit/interpreter/function-counta.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('COUNTA', () => { - it('COUNTA with empty args', () => { - const engine = HyperFormula.buildFromArray([['=COUNTA()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('COUNTA with args', () => { - const engine = HyperFormula.buildFromArray([['=COUNTA(1, B1)', '3.14']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('COUNTA with range', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=COUNTA(A1:A3)']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('COUNTA doesnt count only empty values', () => { - const engine = HyperFormula.buildFromArray([['foo'], ['=""'], [null], ['=TRUE()'], ['=COUNTA(A1:A4)']]) - - expect(engine.getCellValue(adr('A5'))).toEqual(3) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=COUNTA(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(4) - }) - - it('error in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['', ''], - ['=COUNTA(MMULT(A1:B3, A1:B3))'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('doesnt propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=COUNTA(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(4) - }) - - it('should work with explicit error in arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTA(NA())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should work for empty arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTA(1,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) //Compatible with product 2 - }) -}) diff --git a/test/unit/interpreter/function-countblank.spec.ts b/test/unit/interpreter/function-countblank.spec.ts deleted file mode 100644 index eee2a88ae9..0000000000 --- a/test/unit/interpreter/function-countblank.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('COUNTBLANK', () => { - it('with empty args', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTBLANK()'], - ['=COUNTBLANK(,)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - }) - - it('with args', () => { - const engine = HyperFormula.buildFromArray([['=COUNTBLANK(B1, C1)', '3.14']]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('with range', () => { - const engine = HyperFormula.buildFromArray([['1', null, null, '=COUNTBLANK(A1:C1)']]) - expect(engine.getCellValue(adr('D1'))).toEqual(2) - }) - - it('with empty strings', () => { - const engine = HyperFormula.buildFromArray([['', null, null, '=COUNTBLANK(A1:C1)']]) - expect(engine.getCellValue(adr('D1'))).toEqual(2) - }) - - it('does not propagate errors from ranges', () => { - const engine = HyperFormula.buildFromArray([ - [null], - ['=4/0'], - ['=COUNTBLANK(A1:A2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('does not propagate errors from arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTBLANK(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('works even when range vertex is in cycle', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=COUNTBLANK(A1:A3)'], - [null], - ['=COUNTBLANK(A1:A3)'] - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) -}) diff --git a/test/unit/interpreter/function-countif.spec.ts b/test/unit/interpreter/function-countif.spec.ts deleted file mode 100644 index 0e40774772..0000000000 --- a/test/unit/interpreter/function-countif.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {StatType} from '../../../src/statistics' -import {adr, detailedError} from '../testUtils' - -describe('Function COUNTIF', () => { - it('requires 2 arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIF(B1:B3)'], - ['=COUNTIF(B1:B3, ">0", B1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['2'], - ['=COUNTIF(A1:A3, ">=1")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) - - it('works with mixed types', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - ['"1"'], - ['2'], - ['=COUNTIF(A1:A3, "=1")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('use partial cache', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['2', '=COUNTIF(A1:A3, ">=1")'], - ['3', '=COUNTIF(A1:A4, ">=1")'], - ]) - - expect(engine.getCellValue(adr('B3'))).toEqual(2) - expect(engine.getCellValue(adr('B4'))).toEqual(3) - expect(engine.getStats().get(StatType.CRITERION_FUNCTION_PARTIAL_CACHE_USED)).toEqual(1) - }) - - it('use full cache', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '=COUNTIF(A1:A3, ">=1")'], - ['1', '=COUNTIF(A1:A3, ">=1")'], - ['2'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('B2'))).toEqual(2) - expect(engine.getStats().get(StatType.CRITERION_FUNCTION_FULL_CACHE_USED)).toEqual(1) - }) - - it('works for only one cell', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=COUNTIF(A1, ">=1")'], - ['0', '=COUNTIF(A2, ">=1")'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('B2'))).toEqual(0) - }) - - it('error when criterion unparsable', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIF(B1:B2, "> { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIF(10, ">1")'], - ['=COUNTIF(0, ">1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIF(4/0, ">1")'], - ['=COUNTIF(0, 4/0)'], - ['=COUNTIF(4/0, FOOBAR())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works with range values', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '5'], - ['7', '9'], - ['=COUNTIF(A1:B2, ">4")'], - ['=COUNTIF(MMULT(A1:B2, A1:B2), ">50")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('works for matrices', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - [], - ['=COUNTIF(A2:A3, ">0")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) - - it('ignore errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=4/0'], - ['1'], - ['=COUNTIF(A1:A3, "=1")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) - - it('works with a column range reference to an empty sheet', () => { - const hf = HyperFormula.buildFromSheets({ - table1: [], - table2: [['=COUNTIF(table1!A:C, ">1")']], - }) - - expect(hf.getCellValue(adr('A1', 1))).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/function-countifs.spec.ts b/test/unit/interpreter/function-countifs.spec.ts deleted file mode 100644 index 662c2d0368..0000000000 --- a/test/unit/interpreter/function-countifs.spec.ts +++ /dev/null @@ -1,140 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {StatType} from '../../../src/statistics' -import {adr, detailedError} from '../testUtils' - -describe('Function COUNTIFS', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIFS(B1:B3)'], - ['=COUNTIFS(B1:B3, ">0", B1)'], - ['=COUNTIFS(B1:B3, ">0", B1, ">1", 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['2'], - ['=COUNTIFS(A1:A3, ">=1")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) - - it('works for more criteria pairs', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['2', '20'], - ['3', '30'], - ['=COUNTIFS(A1:A3, ">=2", B1:B3, "<=20")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('use partial cache', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['2', '=COUNTIFS(A1:A3, ">=1")'], - ['3', '=COUNTIFS(A1:A4, ">=1")'], - ]) - - expect(engine.getCellValue(adr('B3'))).toEqual(2) - expect(engine.getCellValue(adr('B4'))).toEqual(3) - expect(engine.getStats().get(StatType.CRITERION_FUNCTION_PARTIAL_CACHE_USED)).toEqual(1) - }) - - it('use full cache', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '=COUNTIFS(A1:A3, ">=1")'], - ['1', '=COUNTIFS(A1:A3, ">=1")'], - ['2'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('B2'))).toEqual(2) - expect(engine.getStats().get(StatType.CRITERION_FUNCTION_FULL_CACHE_USED)).toEqual(1) - }) - - it('works for only one cell', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=COUNTIFS(A1, ">=1")'], - ['0', '=COUNTIFS(A2, ">=1")'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('B2'))).toEqual(0) - }) - - it('error when criterion unparsable', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIFS(B1:B2, "> { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIFS(10, ">1")'], - ['=COUNTIFS(0, ">1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTIFS(4/0, ">1")'], - ['=COUNTIFS(0, 4/0)'], - ['=COUNTIFS(4/0, FOOBAR())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works with range values', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '5'], - ['7', '9'], - ['=COUNTIFS(A1:B2, ">4")'], - ['=COUNTIFS(MMULT(A1:B2, A1:B2), ">50")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('works for matrices', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - [], - ['=COUNTIFS(A2:A3, ">0")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) - - it('ignore errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=4/0'], - ['1'], - ['=COUNTIFS(A1:A3, "=1")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/function-countunique.spec.ts b/test/unit/interpreter/function-countunique.spec.ts deleted file mode 100644 index 286f98d3c7..0000000000 --- a/test/unit/interpreter/function-countunique.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function COUNTUNIQUE', () => { - it('error when no arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTUNIQUE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('single number', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTUNIQUE(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('three numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTUNIQUE(2, 1, 2)'], - ['=COUNTUNIQUE(2, 1, 1)'], - ['=COUNTUNIQUE(2, 1, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('theres no coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '="1"'], - ['=COUNTUNIQUE(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(2) - }) - - it('errors in arguments are not propagated', () => { - const engine = HyperFormula.buildFromArray([ - ['=COUNTUNIQUE(5/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('different errors are counted by type', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0', '=COUNTUNIQUE(A1:A4)'], - ['=FOOBAR()'], - ['=5/0'], - ['=BARFOO()'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(2) - }) - - it('empty string doesnt count', () => { - const engine = HyperFormula.buildFromArray([ - ['=""', '=COUNTUNIQUE("", A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('different strings are recognized are counted by type', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', '=COUNTUNIQUE(A1:A4)'], - ['bar'], - ['foo'], - ['bar '], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) - - it('singular values are counted', () => { - const engine = HyperFormula.buildFromArray([ - ['TRUE()', '=COUNTUNIQUE(A1:A6)'], - ['FALSE()'], - [null], - ['TRUE()'], - ['FALSE()'], - [null], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) -}) diff --git a/test/unit/interpreter/function-covariance.p.spec.ts b/test/unit/interpreter/function-covariance.p.spec.ts deleted file mode 100644 index 1c4ba56444..0000000000 --- a/test/unit/interpreter/function-covariance.p.spec.ts +++ /dev/null @@ -1,90 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('COVARIANCE.P', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COVARIANCE.P(B1:B5)'], - ['=COVARIANCE.P(B1:B5, C1:C5, D1:D5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('ranges need to have same amount of elements', () => { - const engine = HyperFormula.buildFromArray([ - ['=COVARIANCE.P(B1:B5, C1:C6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('works (simple)', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['2', '20'], - ['=COVARIANCE.P(A1:A2, B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(2.5) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['=COVARIANCE.P(A2:A2, A2:A2)'], - [null] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.OneValue)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '4'], - ['5', '3'], - ['7', '6'], - ['1', '1'], - ['8', '5'], - ['=COVARIANCE.P(A1:A5, B1:B5)'], - ['=COVARIANCE.P(1,1)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(3.72) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['="2"', '50'], - ['3', '30'], - ['=COVARIANCE.P(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(10) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=COVARIANCE.P(MMULT(A1:B2, A1:B2), MMULT(B1:C2, B1:C2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(122.25) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=4/0', '50'], - ['3', '30'], - ['=COVARIANCE.P(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-covariance.s.spec.ts b/test/unit/interpreter/function-covariance.s.spec.ts deleted file mode 100644 index 10cc4ed085..0000000000 --- a/test/unit/interpreter/function-covariance.s.spec.ts +++ /dev/null @@ -1,92 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('COVARIANCE.S', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=COVARIANCE.S(B1:B5)'], - ['=COVARIANCE.S(B1:B5, C1:C5, D1:D5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('ranges need to have same amount of elements', () => { - const engine = HyperFormula.buildFromArray([ - ['=COVARIANCE.S(B1:B5, C1:C6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('works (simple)', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['2', '20'], - ['=COVARIANCE.S(A1:A2, B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(5) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '4'], - ['5', '3'], - ['7', '6'], - ['1', '1'], - ['8', '5'], - ['=COVARIANCE.S(A1:A5, B1:B5)'] - ]) - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(4.65) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=COVARIANCE.S(A1:A1, B1:B1)'], - ['=COVARIANCE.S(42, 43)'], - ['=COVARIANCE.S("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['="2"', '50'], - ['3', '30'], - ['=COVARIANCE.S(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(20) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=COVARIANCE.S(MMULT(A1:B2, A1:B2), MMULT(B1:C2, B1:C2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(163) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=4/0', '50'], - ['3', '30'], - ['=COVARIANCE.S(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-csc.spec.ts b/test/unit/interpreter/function-csc.spec.ts deleted file mode 100644 index 58ad53a441..0000000000 --- a/test/unit/interpreter/function-csc.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CSC', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=CSC(PI()/2)', '=CSC(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.18839510577812) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=CSC("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=CSC()', '=CSC(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=CSC(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-1.18839510577812) - }) - - it('div/zero', () => { - const engine = HyperFormula.buildFromArray([ - [0, '=CSC(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=CSC(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-csch.spec.ts b/test/unit/interpreter/function-csch.spec.ts deleted file mode 100644 index 5f5fe13db0..0000000000 --- a/test/unit/interpreter/function-csch.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CSCH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=CSCH(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.850918128239322, 11) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=CSCH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=CSCH()', '=CSCH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=CSCH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.850918128239322) - }) - - it('div/zero', () => { - const engine = HyperFormula.buildFromArray([ - [0, '=CSCH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=CSCH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-cumimpt.spec.ts b/test/unit/interpreter/function-cumimpt.spec.ts deleted file mode 100644 index b5f99bb8e7..0000000000 --- a/test/unit/interpreter/function-cumimpt.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CUMIPMT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CUMIPMT(1,1,1,1,1)', '=CUMIPMT(1, 1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=CUMIPMT(1.1%, 12, 100, 1, 5, 0)', '=CUMIPMT(1.1%, 12, 100, 1, 5, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-4.6279374617215) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-3.4895523854812) - }) - - it('should return error when args are incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=CUMIPMT(1.1%, 12, 100, 5, 1, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.EndStartPeriod)) - }) -}) diff --git a/test/unit/interpreter/function-cumprinc.spec.ts b/test/unit/interpreter/function-cumprinc.spec.ts deleted file mode 100644 index 730a98e262..0000000000 --- a/test/unit/interpreter/function-cumprinc.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function CUMPRINC', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=CUMPRINC(1,1,1,1,1)', '=CUMPRINC(1, 1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=CUMPRINC(1.1%, 12, 100, 1, 5, 0)', '=CUMPRINC(1.1%, 12, 100, 1, 5, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-40.07763042) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-40.72960477) - }) - - it('should return error when args are incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=CUMPRINC(1.1%, 12, 100, 5, 1, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.EndStartPeriod)) - }) -}) diff --git a/test/unit/interpreter/function-date.spec.ts b/test/unit/interpreter/function-date.spec.ts deleted file mode 100644 index c7078bef73..0000000000 --- a/test/unit/interpreter/function-date.spec.ts +++ /dev/null @@ -1,222 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {ErrorMessage} from '../../../src/error-message' -import {adr, dateNumberToString, detailedError} from '../testUtils' - -describe('Function DATE', () => { - it('with 3 numerical arguments', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(1900, 1, 1)', '=DATE(1900, 1, 2)', '=DATE(1915, 10, 24)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('01/01/1900') - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(dateNumberToString(engine.getCellValue(adr('B1')), config)).toEqual('02/01/1900') - expect(dateNumberToString(engine.getCellValue(adr('C1')), config)).toEqual('24/10/1915') - }) - - it('truncation', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(1900.9, 1, 1)', '=DATE(1900, 1.9, 2)', '=DATE(1915, 10, 24.9)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('01/01/1900') - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(dateNumberToString(engine.getCellValue(adr('B1')), config)).toEqual('02/01/1900') - expect(dateNumberToString(engine.getCellValue(adr('C1')), config)).toEqual('24/10/1915') - }) - - it('negative', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(-1900, 1, 1)', '=DATE(1901, -1, 2)', '=DATE(2000, -13, 2)', '=DATE(1915, 10, -24)', '=DATE(1900, 1, -100000)', '=DATE(1900, 1, -200000)', '=DATE(-1, 1, 1)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.InvalidDate)) - expect(dateNumberToString(engine.getCellValue(adr('B1')), config)).toEqual('02/11/1900') - expect(dateNumberToString(engine.getCellValue(adr('C1')), config)).toEqual('02/11/1998') - expect(dateNumberToString(engine.getCellValue(adr('D1')), config)).toEqual('06/09/1915') - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.DateBounds)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.DateBounds)) - expect(engine.getCellValue(adr('G1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.DateBounds)) - }) - - it('rollover', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(1900, 14, 28)', '=DATE(1900, 14, 29)', '=DATE(1915, 100, 1000)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('28/02/1901') - expect(dateNumberToString(engine.getCellValue(adr('B1')), config)).toEqual('01/03/1901') - expect(dateNumberToString(engine.getCellValue(adr('C1')), config)).toEqual('25/12/1925') - }) - - it('number of arguments', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(1900, 1)'], - ['=DATE(1900, 1, 1, 1)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with incoercible argument', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE("foo", 1, 1)'], - ['=DATE(1900, "foo", 1)'], - ['=DATE(1900, 1, "foo")'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('with coercible argument', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['="2000"', '=TRUE()'], - ['=DATE(A1, 1, 1)'], - ['=DATE(2000, B1, 1)'], - ['=DATE(2000, 1, B1)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A2')), config)).toEqual('01/01/2000') - expect(dateNumberToString(engine.getCellValue(adr('A3')), config)).toEqual('01/01/2000') - expect(dateNumberToString(engine.getCellValue(adr('A4')), config)).toEqual('01/01/2000') - }) - - it('precedence of errors', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(FOOBAR(), 4/0, 1)'], - ['=DATE(2000, FOOBAR(), 4/0)'], - ['=DATE(2000, 1, FOOBAR())'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) -}) - -describe('Function DATE + leap years', () => { - it('should support nonleap year 2001', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(2001, 02, 29)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('01/03/2001') - }) - - it('should support leap year 2016', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(2016, 02, 29)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('29/02/2016') - }) - - it('should support leap year 1920', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(1920, 02, 29)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('29/02/1920') - }) - - it('should support nonleap year 1900', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(1900, 02, 29)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('01/03/1900') - }) - - it('should support nonleap year 1900 with excel compatibility', () => { - const config = new Config({leapYear1900: true}) - const engine = HyperFormula.buildFromArray([ - ['=DATE(1900, 02, 29)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('29/02/1900') - }) - - it('should support leap year 2400', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(2400, 02, 29)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('29/02/2400') - }) - - it('small year values', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE(0, 02, 29)'], - ['=DATE(1800, 02, 28)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('01/03/1900') - expect(dateNumberToString(engine.getCellValue(adr('A2')), config)).toEqual('28/02/3700') - }) - - it('different nullDate', () => { - const config = new Config({nullDate: {year: 1900, day: 1, month: 1}}) - const engine = HyperFormula.buildFromArray([ - ['=DATE(0, 02, 28)'], - ['=DATE(1800, 02, 28)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('28/02/1900') - expect(dateNumberToString(engine.getCellValue(adr('A2')), config)).toEqual('28/02/3700') - }) - - it('should be leap1900 sensitive', () => { - const config = new Config({leapYear1900: true}) - const engine = HyperFormula.buildFromArray([ - ['=DATE(10, 03, 03)'], - ['=DATE(1800, 02, 28)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('03/03/1909') - expect(dateNumberToString(engine.getCellValue(adr('A2')), config)).toEqual('28/02/3699') - }) - - it('different nullDate, leap1900 sensitive', () => { - const config = new Config({nullDate: {year: 1899, day: 31, month: 12}, leapYear1900: true}) - const engine = HyperFormula.buildFromArray([ - ['=DATE(0, 02, 28)'], - ['=DATE(0, 02, 29)'], - ['=DATE(1800, 02, 28)'], - ], config) - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('28/02/1900') - expect(dateNumberToString(engine.getCellValue(adr('A2')), config)).toEqual('29/02/1900') - expect(dateNumberToString(engine.getCellValue(adr('A3')), config)).toEqual('28/02/3700') - }) - - it('should throw a error in the absence of arguments', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=DATE()'], - ], config) - - expect(dateNumberToString(engine.getCellValue(adr('A1')), config)).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with blanks', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - [null, '', 'string', null, '\''], - ['=DATE(A1, 2, 3)'], - ['=DATE(B1, 2, 3)'], - ['=DATE(C1, 2, 3)'], - ['=DATE(D1, 2, 3)'], - ['=DATE(E1, 2, 3)'], - ], config) - - expect(dateNumberToString(engine.getCellValue(adr('A2')), config)).toEqual('03/02/1900') - expect(dateNumberToString(engine.getCellValue(adr('A3')), config)).toEqual('03/02/1900') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(dateNumberToString(engine.getCellValue(adr('A5')), config)).toEqual('03/02/1900') - expect(dateNumberToString(engine.getCellValue(adr('A6')), config)).toEqual('03/02/1900') - }) -}) diff --git a/test/unit/interpreter/function-datedif.spec.ts b/test/unit/interpreter/function-datedif.spec.ts deleted file mode 100644 index efacfd5f95..0000000000 --- a/test/unit/interpreter/function-datedif.spec.ts +++ /dev/null @@ -1,349 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DATEDIF', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF(1, 2, 3, 4)'], - ['=DATEDIF(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("foo", 1, "Y")'], - ['=DATEDIF(2, "bar", "Y")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('numerical errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF(1, 2, "abcd")'], - ['=DATEDIF(2, 1, "Y")'], - ['=DATEDIF(1.9, 1.8, "Y")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.StartEndDate)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.StartEndDate)) - }) - - it('"D" mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("30/12/2018", "30/12/2018", "D")'], - ['=DATEDIF("28/02/2019", "01/03/2019", "D")'], - ['=DATEDIF("28/02/2020", "01/03/2020", "D")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('ignores time', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("22:00", "36:00", "D")'], - ['=DATEDIF("28/02/2019", "01/03/2019 1:00am", "D")'], - ['=DATEDIF("28/02/2020 2:00pm", "01/03/2020", "D")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('"M" mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("30/12/2018", "30/12/2019", "M")'], - ['=DATEDIF("28/02/2019", "29/03/2019", "M")'], - ['=DATEDIF("29/02/2020", "28/03/2020", "M")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('"YM" mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("30/12/2018", "30/12/2019", "YM")'], - ['=DATEDIF("28/02/2019", "29/03/2019", "YM")'], - ['=DATEDIF("29/02/2020", "28/03/2020", "YM")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('"Y" mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("01/03/2019", "29/02/2020", "Y")'], - ['=DATEDIF("01/03/2019", "28/02/2020", "Y")'], - ['=DATEDIF("28/02/2019", "29/02/2020", "Y")'], - ['=DATEDIF("28/02/2019", "28/02/2020", "Y")'], - ['=DATEDIF("29/02/2020", "28/02/2021", "Y")'], - ['=DATEDIF("29/02/2020", "01/03/2021", "Y")'], - ['=DATEDIF("28/02/2020", "28/02/2021", "Y")'], - ['=DATEDIF("28/02/2020", "01/03/2021", "Y")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - expect(engine.getCellValue(adr('A8'))).toEqual(1) - }) - - it('"MD" mode #1', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/03/2019", "29/02/2020", "MD")'], - ['=DATEDIF("28/03/2019", "28/02/2020", "MD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('"MD" mode #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/03/2016", "01/05/2020", "MD")'], - ['=DATEDIF("28/02/2016", "01/05/2020", "MD")'], - ['=DATEDIF("28/02/2015", "01/05/2020", "MD")'], - ['=DATEDIF("28/01/2016", "01/05/2020", "MD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('"MD" mode #3', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/03/2016", "01/03/2020", "MD")'], - ['=DATEDIF("28/02/2016", "01/03/2020", "MD")'], - ['=DATEDIF("28/02/2015", "01/03/2020", "MD")'], - ['=DATEDIF("28/01/2016", "01/03/2020", "MD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) - - it('"MD" mode #4', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/03/2016", "01/03/2021", "MD")'], - ['=DATEDIF("28/02/2016", "01/03/2021", "MD")'], - ['=DATEDIF("28/02/2015", "01/03/2021", "MD")'], - ['=DATEDIF("28/01/2016", "01/03/2021", "MD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('"MD" mode #5', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/03/2016", "01/02/2020", "MD")'], - ['=DATEDIF("28/02/2016", "01/02/2020", "MD")'], - ['=DATEDIF("28/02/2015", "01/02/2020", "MD")'], - ['=DATEDIF("28/01/2016", "01/02/2020", "MD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - expect(engine.getCellValue(adr('A2'))).toEqual(4) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('"MD" mode #6', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/03/2016", "01/01/2020", "MD")'], - ['=DATEDIF("28/02/2016", "01/01/2020", "MD")'], - ['=DATEDIF("28/02/2015", "01/01/2020", "MD")'], - ['=DATEDIF("28/01/2016", "01/01/2020", "MD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - expect(engine.getCellValue(adr('A2'))).toEqual(4) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('"MD" mode negative result', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("31/01/2020", "01/03/2020", "MD")'], - ['=DATEDIF("31/01/2021", "01/03/2021", "MD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-1) - expect(engine.getCellValue(adr('A2'))).toEqual(-2) - }) - - it('"YD" mode #1', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("27/02/2016", "27/02/2020", "YD")'], - ['=DATEDIF("27/02/2016", "28/02/2020", "YD")'], - ['=DATEDIF("27/02/2016", "29/02/2020", "YD")'], - ['=DATEDIF("27/02/2016", "01/03/2020", "YD")'], - ['=DATEDIF("27/02/2016", "27/02/2021", "YD")'], - ['=DATEDIF("27/02/2016", "28/02/2021", "YD")'], - ['=DATEDIF("27/02/2016", "01/03/2021", "YD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(2) - }) - - it('"YD" mode #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/02/2016", "27/02/2020", "YD")'], - ['=DATEDIF("28/02/2016", "28/02/2020", "YD")'], - ['=DATEDIF("28/02/2016", "29/02/2020", "YD")'], - ['=DATEDIF("28/02/2016", "01/03/2020", "YD")'], - ['=DATEDIF("28/02/2016", "27/02/2021", "YD")'], - ['=DATEDIF("28/02/2016", "28/02/2021", "YD")'], - ['=DATEDIF("28/02/2016", "01/03/2021", "YD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(365) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(2) - expect(engine.getCellValue(adr('A5'))).toEqual(365) - expect(engine.getCellValue(adr('A6'))).toEqual(0) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - }) - - it('"YD" mode #3', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("29/02/2016", "27/02/2020", "YD")'], - ['=DATEDIF("29/02/2016", "28/02/2020", "YD")'], - ['=DATEDIF("29/02/2016", "29/02/2020", "YD")'], - ['=DATEDIF("29/02/2016", "01/03/2020", "YD")'], - ['=DATEDIF("29/02/2016", "27/02/2021", "YD")'], - ['=DATEDIF("29/02/2016", "28/02/2021", "YD")'], - ['=DATEDIF("29/02/2016", "01/03/2021", "YD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(364) - expect(engine.getCellValue(adr('A2'))).toEqual(365) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(364) - expect(engine.getCellValue(adr('A6'))).toEqual(365) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - }) - - it('"YD" mode #4', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("01/03/2016", "27/02/2020", "YD")'], - ['=DATEDIF("01/03/2016", "28/02/2020", "YD")'], - ['=DATEDIF("01/03/2016", "29/02/2020", "YD")'], - ['=DATEDIF("01/03/2016", "01/03/2020", "YD")'], - ['=DATEDIF("01/03/2016", "27/02/2021", "YD")'], - ['=DATEDIF("01/03/2016", "28/02/2021", "YD")'], - ['=DATEDIF("01/03/2016", "01/03/2021", "YD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(363) - expect(engine.getCellValue(adr('A2'))).toEqual(364) - expect(engine.getCellValue(adr('A3'))).toEqual(365) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - expect(engine.getCellValue(adr('A5'))).toEqual(363) - expect(engine.getCellValue(adr('A6'))).toEqual(364) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - }) - - it('"YD" mode #5', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("27/02/2015", "27/02/2020", "YD")'], - ['=DATEDIF("27/02/2015", "28/02/2020", "YD")'], - ['=DATEDIF("27/02/2015", "29/02/2020", "YD")'], - ['=DATEDIF("27/02/2015", "01/03/2020", "YD")'], - ['=DATEDIF("27/02/2015", "27/02/2021", "YD")'], - ['=DATEDIF("27/02/2015", "28/02/2021", "YD")'], - ['=DATEDIF("27/02/2015", "01/03/2021", "YD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(2) - }) - - it('"YD" mode #6', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("28/02/2015", "27/02/2020", "YD")'], - ['=DATEDIF("28/02/2015", "28/02/2020", "YD")'], - ['=DATEDIF("28/02/2015", "29/02/2020", "YD")'], - ['=DATEDIF("28/02/2015", "01/03/2020", "YD")'], - ['=DATEDIF("28/02/2015", "27/02/2021", "YD")'], - ['=DATEDIF("28/02/2015", "28/02/2021", "YD")'], - ['=DATEDIF("28/02/2015", "01/03/2021", "YD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(364) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(2) - expect(engine.getCellValue(adr('A5'))).toEqual(364) - expect(engine.getCellValue(adr('A6'))).toEqual(0) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - }) - - it('"YD" mode #7', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF("01/03/2015", "27/02/2020", "YD")'], - ['=DATEDIF("01/03/2015", "28/02/2020", "YD")'], - ['=DATEDIF("01/03/2015", "29/02/2020", "YD")'], - ['=DATEDIF("01/03/2015", "01/03/2020", "YD")'], - ['=DATEDIF("01/03/2015", "27/02/2021", "YD")'], - ['=DATEDIF("01/03/2015", "28/02/2021", "YD")'], - ['=DATEDIF("01/03/2015", "01/03/2021", "YD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(363) - expect(engine.getCellValue(adr('A2'))).toEqual(364) - expect(engine.getCellValue(adr('A3'))).toEqual(365) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - expect(engine.getCellValue(adr('A5'))).toEqual(363) - expect(engine.getCellValue(adr('A6'))).toEqual(364) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - }) - - //inconsistency with product 1 - it('fails for negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEDIF(-1, 0, "Y")'], - ['=DATEDIF(0, -1, "M")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-datevalue.spec.ts b/test/unit/interpreter/function-datevalue.spec.ts deleted file mode 100644 index 813bf39704..0000000000 --- a/test/unit/interpreter/function-datevalue.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DATEVALUE', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=DATEVALUE("foo")', '=DATEVALUE(1)', '=DATEVALUE(1, 2)', '=DATEVALUE()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IncorrectDateTime)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IncorrectDateTime)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=DATEVALUE("31/12/1899")', '=DATEVALUE("01/01/1900")', '=DATEVALUE("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('C1'))).toEqual(43465) - }) - - it('ignores time', () => { - const engine = HyperFormula.buildFromArray([['=DATEVALUE("2:00pm")', '=DATEVALUE("31/12/2018 2:00pm")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('B1'))).toEqual(43465) - }) - - it('border case', () => { - const engine = HyperFormula.buildFromArray([['=DATEVALUE("25:00")', '=DATEVALUE("31/12/2018 25:00")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('B1'))).toEqual(43466) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEVALUE(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return NUMBER_DATE', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATEVALUE("25/02/1991")'], - ]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_DATE) - }) -}) diff --git a/test/unit/interpreter/function-day.spec.ts b/test/unit/interpreter/function-day.spec.ts deleted file mode 100644 index b362d867b0..0000000000 --- a/test/unit/interpreter/function-day.spec.ts +++ /dev/null @@ -1,247 +0,0 @@ -import {HyperFormula, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DAY', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=DAY("foo")', '=DAY("12/30/2018")', '=DAY(1, 2)', '=DAY()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([['=DAY(0)', '=DAY(2)', '=DAY(43465)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(30) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(31) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=DAY("31/12/1899")', '=DAY("01/01/1900")', '=DAY("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(31) - }) - - it('use datenumber coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(TRUE())'], - ['=DAY(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('A2'))).toEqual(31) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('test for days in month, start of month', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(DATE(2021, 1, 1))'], - ['=DAY(DATE(2021, 2, 1))'], - ['=DAY(DATE(2021, 3, 1))'], - ['=DAY(DATE(2021, 4, 1))'], - ['=DAY(DATE(2021, 5, 1))'], - ['=DAY(DATE(2021, 6, 1))'], - ['=DAY(DATE(2021, 7, 1))'], - ['=DAY(DATE(2021, 8, 1))'], - ['=DAY(DATE(2021, 9, 1))'], - ['=DAY(DATE(2021, 10, 1))'], - ['=DAY(DATE(2021, 11, 1))'], - ['=DAY(DATE(2021, 12, 1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - expect(engine.getCellValue(adr('A8'))).toEqual(1) - expect(engine.getCellValue(adr('A9'))).toEqual(1) - expect(engine.getCellValue(adr('A10'))).toEqual(1) - expect(engine.getCellValue(adr('A11'))).toEqual(1) - expect(engine.getCellValue(adr('A12'))).toEqual(1) - }) - - it('test for days in month, end of month', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(DATE(2021, 1, 31))'], - ['=DAY(DATE(2021, 2, 28))'], - ['=DAY(DATE(2021, 3, 31))'], - ['=DAY(DATE(2021, 4, 30))'], - ['=DAY(DATE(2021, 5, 31))'], - ['=DAY(DATE(2021, 6, 30))'], - ['=DAY(DATE(2021, 7, 31))'], - ['=DAY(DATE(2021, 8, 31))'], - ['=DAY(DATE(2021, 9, 30))'], - ['=DAY(DATE(2021, 10, 31))'], - ['=DAY(DATE(2021, 11, 30))'], - ['=DAY(DATE(2021, 12, 31))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('A2'))).toEqual(28) - expect(engine.getCellValue(adr('A3'))).toEqual(31) - expect(engine.getCellValue(adr('A4'))).toEqual(30) - expect(engine.getCellValue(adr('A5'))).toEqual(31) - expect(engine.getCellValue(adr('A6'))).toEqual(30) - expect(engine.getCellValue(adr('A7'))).toEqual(31) - expect(engine.getCellValue(adr('A8'))).toEqual(31) - expect(engine.getCellValue(adr('A9'))).toEqual(30) - expect(engine.getCellValue(adr('A10'))).toEqual(31) - expect(engine.getCellValue(adr('A11'))).toEqual(30) - expect(engine.getCellValue(adr('A12'))).toEqual(31) - }) - - it('test for days in month, end of month+1', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(DATE(2021, 1, 31)+1)'], - ['=DAY(DATE(2021, 2, 28)+1)'], - ['=DAY(DATE(2021, 3, 31)+1)'], - ['=DAY(DATE(2021, 4, 30)+1)'], - ['=DAY(DATE(2021, 5, 31)+1)'], - ['=DAY(DATE(2021, 6, 30)+1)'], - ['=DAY(DATE(2021, 7, 31)+1)'], - ['=DAY(DATE(2021, 8, 31)+1)'], - ['=DAY(DATE(2021, 9, 30)+1)'], - ['=DAY(DATE(2021, 10, 31)+1)'], - ['=DAY(DATE(2021, 11, 30)+1)'], - ['=DAY(DATE(2021, 12, 31)+1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - expect(engine.getCellValue(adr('A8'))).toEqual(1) - expect(engine.getCellValue(adr('A9'))).toEqual(1) - expect(engine.getCellValue(adr('A10'))).toEqual(1) - expect(engine.getCellValue(adr('A11'))).toEqual(1) - expect(engine.getCellValue(adr('A12'))).toEqual(1) - }) - - it('test for days in month, start of month, leap year', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(DATE(2020, 1, 1))'], - ['=DAY(DATE(2020, 2, 1))'], - ['=DAY(DATE(2020, 3, 1))'], - ['=DAY(DATE(2020, 4, 1))'], - ['=DAY(DATE(2020, 5, 1))'], - ['=DAY(DATE(2020, 6, 1))'], - ['=DAY(DATE(2020, 7, 1))'], - ['=DAY(DATE(2020, 8, 1))'], - ['=DAY(DATE(2020, 9, 1))'], - ['=DAY(DATE(2020, 10, 1))'], - ['=DAY(DATE(2020, 11, 1))'], - ['=DAY(DATE(2020, 12, 1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - expect(engine.getCellValue(adr('A8'))).toEqual(1) - expect(engine.getCellValue(adr('A9'))).toEqual(1) - expect(engine.getCellValue(adr('A10'))).toEqual(1) - expect(engine.getCellValue(adr('A11'))).toEqual(1) - expect(engine.getCellValue(adr('A12'))).toEqual(1) - }) - - it('test for days in month, end of month, leap year', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(DATE(2020, 1, 31))'], - ['=DAY(DATE(2020, 2, 29))'], - ['=DAY(DATE(2020, 3, 31))'], - ['=DAY(DATE(2020, 4, 30))'], - ['=DAY(DATE(2020, 5, 31))'], - ['=DAY(DATE(2020, 6, 30))'], - ['=DAY(DATE(2020, 7, 31))'], - ['=DAY(DATE(2020, 8, 31))'], - ['=DAY(DATE(2020, 9, 30))'], - ['=DAY(DATE(2020, 10, 31))'], - ['=DAY(DATE(2020, 11, 30))'], - ['=DAY(DATE(2020, 12, 31))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('A2'))).toEqual(29) - expect(engine.getCellValue(adr('A3'))).toEqual(31) - expect(engine.getCellValue(adr('A4'))).toEqual(30) - expect(engine.getCellValue(adr('A5'))).toEqual(31) - expect(engine.getCellValue(adr('A6'))).toEqual(30) - expect(engine.getCellValue(adr('A7'))).toEqual(31) - expect(engine.getCellValue(adr('A8'))).toEqual(31) - expect(engine.getCellValue(adr('A9'))).toEqual(30) - expect(engine.getCellValue(adr('A10'))).toEqual(31) - expect(engine.getCellValue(adr('A11'))).toEqual(30) - expect(engine.getCellValue(adr('A12'))).toEqual(31) - }) - - it('test for days in month, end of month+1, leap year', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(DATE(2020, 1, 31)+1)'], - ['=DAY(DATE(2020, 2, 29)+1)'], - ['=DAY(DATE(2020, 3, 31)+1)'], - ['=DAY(DATE(2020, 4, 30)+1)'], - ['=DAY(DATE(2020, 5, 31)+1)'], - ['=DAY(DATE(2020, 6, 30)+1)'], - ['=DAY(DATE(2020, 7, 31)+1)'], - ['=DAY(DATE(2020, 8, 31)+1)'], - ['=DAY(DATE(2020, 9, 30)+1)'], - ['=DAY(DATE(2020, 10, 31)+1)'], - ['=DAY(DATE(2020, 11, 30)+1)'], - ['=DAY(DATE(2020, 12, 31)+1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - expect(engine.getCellValue(adr('A8'))).toEqual(1) - expect(engine.getCellValue(adr('A9'))).toEqual(1) - expect(engine.getCellValue(adr('A10'))).toEqual(1) - expect(engine.getCellValue(adr('A11'))).toEqual(1) - expect(engine.getCellValue(adr('A12'))).toEqual(1) - }) - - it('returns 30 when its argument is a reference to an empty cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(B1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(30) - }) - - it('returns 31 when its argument is a reference to an empty cell and the engine is configured to use 1899-12-31 as a null year', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(B1)'], - ], { - leapYear1900: true, - nullDate: { year: 1899, month: 12, day: 31 }, - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(31) - }) -}) diff --git a/test/unit/interpreter/function-days.spec.ts b/test/unit/interpreter/function-days.spec.ts deleted file mode 100644 index d31d00987c..0000000000 --- a/test/unit/interpreter/function-days.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DAYS', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS(1, 2, 3)'], - ['=DAYS(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS("foo", 1)'], - ['=DAYS(2, "bar")'], - ['=DAYS(2, "12/30/2018")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work for strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS("30/12/2018", "30/12/2018")'], - ['=DAYS("31/12/2018", "30/12/2018")'], - ['=DAYS("30/12/2018", "31/12/2018")'], - ['=DAYS("28/02/2017", "28/02/2016")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(-1) - expect(engine.getCellValue(adr('A4'))).toEqual(366) - }) - it('ignores time', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS("30/12/2018 1:00am", "30/12/2018 11:00pm")'], - ['=DAYS("31/12/2018 1:00am", "30/12/2018 11:00pm")'], - ['=DAYS("30/12/2018 11:00pm", "31/12/2018 1:00am")'], - ['=DAYS("28/02/2017 11:00pm", "28/02/2016 1:00am")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(-1) - expect(engine.getCellValue(adr('A4'))).toEqual(366) - }) - - it('should work for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS(20, 10)'], - ['=DAYS(12346, "28/02/2016")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(10) - expect(engine.getCellValue(adr('A2'))).toEqual(-30082) - }) - - //inconsistency with product 1 - it('fails for negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS(-1, 0)'], - ['=DAYS(0, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-days360.spec.ts b/test/unit/interpreter/function-days360.spec.ts deleted file mode 100644 index 0ae351719a..0000000000 --- a/test/unit/interpreter/function-days360.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DAYS360', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS360(1, 2, 3, 4)'], - ['=DAYS360(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS360("foo", 1, TRUE())'], - ['=DAYS360(2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('US mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS360("30/03/2020", "31/03/2020")'], - ['=DAYS360("28/02/2020", "29/02/2020")'], - ['=DAYS360("29/02/2020", "01/03/2020")'], - ['=DAYS360("28/02/2021", "01/03/2021")'], - ['=DAYS360("31/03/2020", "30/03/2020")'], - ['=DAYS360("29/02/2020", "28/02/2020")'], - ['=DAYS360("01/03/2020", "29/02/2020")'], - ['=DAYS360("01/03/2021", "28/02/2021")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(-2) - expect(engine.getCellValue(adr('A7'))).toEqual(-2) - expect(engine.getCellValue(adr('A8'))).toEqual(-3) - }) - - it('EU mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAYS360("30/03/2020", "31/03/2020", TRUE())'], - ['=DAYS360("28/02/2020", "29/02/2020", TRUE())'], - ['=DAYS360("29/02/2020", "01/03/2020", TRUE())'], - ['=DAYS360("28/02/2021", "01/03/2021", TRUE())'], - ['=DAYS360("31/03/2020", "30/03/2020", TRUE())'], - ['=DAYS360("29/02/2020", "28/02/2020", TRUE())'], - ['=DAYS360("01/03/2020", "29/02/2020", TRUE())'], - ['=DAYS360("01/03/2021", "28/02/2021", TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(-1) - expect(engine.getCellValue(adr('A7'))).toEqual(-2) - expect(engine.getCellValue(adr('A8'))).toEqual(-3) - }) -}) diff --git a/test/unit/interpreter/function-db.spec.ts b/test/unit/interpreter/function-db.spec.ts deleted file mode 100644 index a6bc17fb33..0000000000 --- a/test/unit/interpreter/function-db.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DB', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DB(1, 1, 1)', '=DB(1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=DB(10000, 50, 10, 2, 12)', - '=DB(10000, 50, 10, 2)', - '=DB(10000, 50, 10, 2, 7)'], - ['=DB(10000, 50, 10, 1, 12)', - '=DB(10000, 50, 10, 1, 7)'], - ['=DB(10000, 50, 10, 10, 12)', - '=DB(10000, 50, 10, 10, 7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2420.79) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(2420.79) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(3124.63) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(4110.00) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(2397.50) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(35.07) - expect(engine.getCellValue(adr('B3'))).toBeCloseTo(45.26) - }) - - it('compatibility', () => { - const engine = HyperFormula.buildFromArray([ - ['=DB(1000000, 100000, 6, 7, 7)', - '=DB(1000000, 100000, 6, 8, 7)', - '=DB(1000000, 100000, 6, 7)', ], - ]) - //product #1 returns #NUM! instead of an actual value - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(15845.10) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.PeriodLong)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.PeriodLong)) - }) - - it('should return zero if salvage >= cost', () => { - const engine = HyperFormula.buildFromArray([ - ['=DB(10000, 10000, 10, 2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/function-ddb.spec.ts b/test/unit/interpreter/function-ddb.spec.ts deleted file mode 100644 index 28901dbfb5..0000000000 --- a/test/unit/interpreter/function-ddb.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DDB', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DDB(1, 1, 1)', '=DDB(1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=DDB(10000, 50, 10, 2, 1)', - '=DDB(10000, 50, 10, 2)', - '=DDB(10000, 50, 10, 2, 1.2)', - '=DDB(10000, 50, 10, 2, 2.5)', - '=DDB(10000, 10010, 10, 2, 2.5)', - '=DDB(2, 1, 20, 10, 60)', - ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(900) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1600) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(1056) - expect(engine.getCellValue(adr('D1'))).toBeCloseTo(1875) - expect(engine.getCellValue(adr('E1'))).toBeCloseTo(0) - expect(engine.getCellValue(adr('F1'))).toBeCloseTo(0) - }) - - it('should return correct value for fractional period', () => { - const engine = HyperFormula.buildFromArray([ - ['=DDB(10000, 50, 10, 2.5, 1)', - '=DDB(10000, 50, 10, 2.1)', - '=DDB(10000, 50, 10, 2.9, 1.2)', - '=DDB(10000, 50, 10, 2.5, 2.5)', - '=DDB(10000, 10010, 10, 2.1, 2.5)', - '=DDB(2, 1, 20, 10.9, 60)', - '=DDB(2, 1, 20, 1, 60)', - ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(853.8149682, 6) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1564.69243, 6) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(941.2355527, 6) - expect(engine.getCellValue(adr('D1'))).toBeCloseTo(1623.797632, 6) - expect(engine.getCellValue(adr('E1'))).toBeCloseTo(0) - expect(engine.getCellValue(adr('F1'))).toBeCloseTo(0) - expect(engine.getCellValue(adr('G1'))).toEqual(1) - }) - - it('should return error when args are incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=DDB(10000, 50, 2, 10, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM)) - }) -}) diff --git a/test/unit/interpreter/function-dec2bin.spec.ts b/test/unit/interpreter/function-dec2bin.spec.ts deleted file mode 100644 index 4d267b4307..0000000000 --- a/test/unit/interpreter/function-dec2bin.spec.ts +++ /dev/null @@ -1,117 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function DEC2BIN', () => { - it('should return error when wrong type of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN(1)'], - ['=DEC2BIN(2)'], - ['=DEC2BIN(98)'], - ['=DEC2BIN(-12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('10') - expect(engine.getCellValue(adr('A3'))).toEqual('1100010') - expect(engine.getCellValue(adr('A4'))).toEqual('1111110100') - }) - - it('should work for numeric strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN("123")'], - ['=DEC2BIN("-15")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1111011') - expect(engine.getCellValue(adr('A2'))).toEqual('1111110001') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['12'], - ['=DEC2BIN(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('1100') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN(123)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should work for numbers between -512 and 511', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN(-513)'], - ['=DEC2BIN(-512)'], - ['=DEC2BIN(511)'], - ['=DEC2BIN(512)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseSmall)) - expect(engine.getCellValue(adr('A2'))).toEqual('1000000000') - expect(engine.getCellValue(adr('A3'))).toEqual('111111111') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN(2, 8)'], - ['=DEC2BIN(5, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00000010') - expect(engine.getCellValue(adr('A2'))).toEqual('0101') - }) - - it('should fail if the result is longer than the desired number of digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN(50, 1)'], - ['=DEC2BIN(777, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - }) - - it('should ignore second argument for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN(-2, 1)'], - ['=DEC2BIN(-2, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1111111110') - expect(engine.getCellValue(adr('A2'))).toEqual('1111111110') - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2BIN(2, 0)'], - ['=DEC2BIN(-2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-dec2hex.spec.ts b/test/unit/interpreter/function-dec2hex.spec.ts deleted file mode 100644 index 4ef24cff81..0000000000 --- a/test/unit/interpreter/function-dec2hex.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function DEC2HEX', () => { - it('should return error when wrong type of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX(1)'], - ['=DEC2HEX(50)'], - ['=DEC2HEX(122)'], - ['=DEC2HEX(-154)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('32') - expect(engine.getCellValue(adr('A3'))).toEqual('7A') - expect(engine.getCellValue(adr('A4'))).toEqual('FFFFFFFF66') - }) - - it('should work for numeric strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX("123")'], - ['=DEC2HEX("-15")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('7B') - expect(engine.getCellValue(adr('A2'))).toEqual('FFFFFFFFF1') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['12'], - ['=DEC2HEX(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('C') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX(123)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should work for numbers fitting in 10 bits', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX(-549755813889)'], - ['=DEC2HEX(-549755813888)'], - ['=DEC2HEX(549755813887)'], - ['=DEC2HEX(549755813888)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseSmall)) - expect(engine.getCellValue(adr('A2'))).toEqual('8000000000') - expect(engine.getCellValue(adr('A3'))).toEqual('7FFFFFFFFF') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX(2, 8)'], - ['=DEC2HEX(20, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00000002') - expect(engine.getCellValue(adr('A2'))).toEqual('0014') - }) - - it('should ignore second argument for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX(-2, 1)'], - ['=DEC2HEX(-2, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('FFFFFFFFFE') - expect(engine.getCellValue(adr('A2'))).toEqual('FFFFFFFFFE') - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2HEX(2, 0)'], - ['=DEC2HEX(-2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-dec2oct.spec.ts b/test/unit/interpreter/function-dec2oct.spec.ts deleted file mode 100644 index 0e0b326812..0000000000 --- a/test/unit/interpreter/function-dec2oct.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function DEC2OCT', () => { - it('should return error when wrong type of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT(1)'], - ['=DEC2OCT(10)'], - ['=DEC2OCT(98)'], - ['=DEC2OCT(-12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('12') - expect(engine.getCellValue(adr('A3'))).toEqual('142') - expect(engine.getCellValue(adr('A4'))).toEqual('7777777764') - }) - - it('should work for numeric strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT("123")'], - ['=DEC2OCT("-15")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('173') - expect(engine.getCellValue(adr('A2'))).toEqual('7777777761') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['12'], - ['=DEC2OCT(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('14') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT(123)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should work for numbers fitting in 10 bits', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT(-536870913)'], - ['=DEC2OCT(-536870912)'], - ['=DEC2OCT(536870911)'], - ['=DEC2OCT(536870912)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseSmall)) - expect(engine.getCellValue(adr('A2'))).toEqual('4000000000') - expect(engine.getCellValue(adr('A3'))).toEqual('3777777777') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT(2, 8)'], - ['=DEC2OCT(5, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00000002') - expect(engine.getCellValue(adr('A2'))).toEqual('0005') - }) - - it('should ignore second argument for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT(-2, 1)'], - ['=DEC2OCT(-2, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('7777777776') - expect(engine.getCellValue(adr('A2'))).toEqual('7777777776') - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEC2OCT(2, 0)'], - ['=DEC2OCT(-2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-decimal.spec.ts b/test/unit/interpreter/function-decimal.spec.ts deleted file mode 100644 index 8e3e37346f..0000000000 --- a/test/unit/interpreter/function-decimal.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DECIMAL', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DECIMAL(123)'], - ['=DECIMAL("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error when value does not correspond to base', () => { - const engine = HyperFormula.buildFromArray([ - ['=DECIMAL(12, 2)'], - ['=DECIMAL("123XYZ", 33)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=DECIMAL(10, 2)'], - ['=DECIMAL("11111111111111111111111111111111110", 2)'], - ['=DECIMAL(123, 4)'], - ['=DECIMAL("C0FFEE", 16)'], - ['=DECIMAL("C0FFEE", 25)'], - ['=DECIMAL("89WPQ", 33)'], - ['=DECIMAL("123XYZ", 36)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(34359738366) - expect(engine.getCellValue(adr('A3'))).toEqual(27) - expect(engine.getCellValue(adr('A4'))).toEqual(12648430) - expect(engine.getCellValue(adr('A5'))).toEqual(117431614) - expect(engine.getCellValue(adr('A6'))).toEqual(9846500) - expect(engine.getCellValue(adr('A7'))).toEqual(64009403) - }) - - it('should work for of max length 255', () => { - const longNumber = '1'.repeat(255) - const tooLongNumber = '1'.repeat(256) - const engine = HyperFormula.buildFromArray([ - [`=DECIMAL(\"${longNumber}\", 2)`], - [`=DECIMAL(\"${tooLongNumber}\", 2)`], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(5.78960446186581e+76, -66) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - }) - - it('should work only for bases from 2 to 36', () => { - const engine = HyperFormula.buildFromArray([ - ['=DECIMAL("0", 0)'], - ['=DECIMAL("10", 2)'], - ['=DECIMAL("XYZ", 36)'], - ['=DECIMAL("XYZ", 37)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(44027) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('should return number', () => { - const engine = HyperFormula.buildFromArray([ - ['=DECIMAL("123", 4)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toEqual(CellValueType.NUMBER) - }) -}) diff --git a/test/unit/interpreter/function-degrees.spec.ts b/test/unit/interpreter/function-degrees.spec.ts deleted file mode 100644 index ecd7fc2475..0000000000 --- a/test/unit/interpreter/function-degrees.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DEGREES', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEGREES(0)', '=DEGREES(3.14)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(179.9087477) - }) - - it('given wrong argument type', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEGREES("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="3.14"', '=DEGREES(A1)'], - ['=TRUE()', '=DEGREES(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(179.9087477) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(57.29577951) - }) - - it('given wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEGREES()'], - ['=DEGREES(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEGREES(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-delta.spec.ts b/test/unit/interpreter/function-delta.spec.ts deleted file mode 100644 index 9a5559f847..0000000000 --- a/test/unit/interpreter/function-delta.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DELTA', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DELTA()'], - ['=DELTA(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DELTA("foo")'], - ['=DELTA(1, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should compare to 0 if one argument provided', () => { - const engine = HyperFormula.buildFromArray([ - ['=DELTA(0)'], - ['=DELTA("123")'], - ['=DELTA(FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('should compare two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DELTA(1, 0)'], - ['=DELTA(2, 2)'], - ['=DELTA(123, "123")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('should return number', () => { - const engine = HyperFormula.buildFromArray([ - ['=DELTA(3, 3)'], - ['=DELTA("123")'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toEqual(CellValueType.NUMBER) - expect(engine.getCellValueType(adr('A2'))).toEqual(CellValueType.NUMBER) - }) -}) diff --git a/test/unit/interpreter/function-devsq.spec.ts b/test/unit/interpreter/function-devsq.spec.ts deleted file mode 100644 index 5eb51652e2..0000000000 --- a/test/unit/interpreter/function-devsq.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {adr, detailedError} from '../testUtils' - -describe('Function DEVSQ', () => { - it('single number', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEVSQ(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('two numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEVSQ(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) - - it('more numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEVSQ(3, 1, 2, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(10) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '9', '0'], - ['=DEVSQ(A1:C1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(54) - }) - - it('propagates error from regular argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=DEVSQ(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('propagates first error from range argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=FOO(', '=DEVSQ(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - //inconsistency with product #2 - it('returns 0 for empty ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEVSQ(A2:A3)'], - [null], - [null], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - /** - * product #1 does not coerce the input - */ - it('does coercions of nonnumeric explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEVSQ(TRUE(),FALSE(),)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.666666666666667, 6) - }) - - it('ignores nonnumeric values in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=DEVSQ(A2:D2)'], - [0, 1, false, null, '\'0'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) -}) diff --git a/test/unit/interpreter/function-dollarde.spec.ts b/test/unit/interpreter/function-dollarde.spec.ts deleted file mode 100644 index 5c2ba5874e..0000000000 --- a/test/unit/interpreter/function-dollarde.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DOLLARDE', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DOLLARDE(1)', '=DOLLARDE(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('div/0 when second argument too small', () => { - const engine = HyperFormula.buildFromArray([ - ['=DOLLARDE(1,0)', '=DOLLARDE(1, 0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - [ - '=DOLLARDE(1.01, 8)', - '=DOLLARDE(1.0000001, 8.9)', - '=DOLLARDE(1.1, 100001)', - '=DOLLARDE(1.1, 100000)', - '=DOLLARDE(123.456, 2)', - '=DOLLARDE(1.9, 2)', - '=DOLLARDE(1.01,10.1)', - ], - [ - '=DOLLARDE(-1.01, 8)', - '=DOLLARDE(-1.0000001, 8.9)', - '=DOLLARDE(-1.1, 100001)', - '=DOLLARDE(-1.1, 100000)', - '=DOLLARDE(-123.456, 2)', - '=DOLLARDE(-1.9, 2)', - '=DOLLARDE(-1.01,10.1)', - ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.0125) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.000000125) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(1.9999900001) - expect(engine.getCellValue(adr('D1'))).toBeCloseTo(1.1) - expect(engine.getCellValue(adr('E1'))).toBeCloseTo(125.28) - expect(engine.getCellValue(adr('F1'))).toBeCloseTo(5.5) - expect(engine.getCellValue(adr('G1'))).toBeCloseTo(1.01) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-1.0125) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(-1.000000125) - expect(engine.getCellValue(adr('C2'))).toBeCloseTo(-1.9999900001) - expect(engine.getCellValue(adr('D2'))).toBeCloseTo(-1.1) - expect(engine.getCellValue(adr('E2'))).toBeCloseTo(-125.28) - expect(engine.getCellValue(adr('F2'))).toBeCloseTo(-5.5) - expect(engine.getCellValue(adr('G2'))).toBeCloseTo(-1.01) - }) -}) diff --git a/test/unit/interpreter/function-dollarfr.spec.ts b/test/unit/interpreter/function-dollarfr.spec.ts deleted file mode 100644 index b90a6296d3..0000000000 --- a/test/unit/interpreter/function-dollarfr.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function DOLLARFR', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DOLLARFR(1)', '=DOLLARFR(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('div/0 when second argument too small', () => { - const engine = HyperFormula.buildFromArray([ - ['=DOLLARFR(1,0)', '=DOLLARFR(1, 0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - [ - '=DOLLARFR(1.0125, 8)', - '=DOLLARFR(1.000000125, 8.9)', - '=DOLLARFR(1.9999900001, 100001)', - '=DOLLARFR(1.1, 100000)', - '=DOLLARFR(125.28, 2)', - '=DOLLARFR(5.5, 2)', - '=DOLLARFR(1.01,10.1)', - ], - [ - '=DOLLARFR(-1.0125, 8)', - '=DOLLARFR(-1.000000125, 8.9)', - '=DOLLARFR(-1.9999900001, 100001)', - '=DOLLARFR(-1.1, 100000)', - '=DOLLARFR(-125.28, 2)', - '=DOLLARFR(-5.5, 2)', - '=DOLLARFR(-1.01,10.1)', - ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.01) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.0000001) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(1.1) - expect(engine.getCellValue(adr('D1'))).toBeCloseTo(1.1) - expect(engine.getCellValue(adr('E1'))).toBeCloseTo(125.056) - expect(engine.getCellValue(adr('F1'))).toBeCloseTo(5.1) - expect(engine.getCellValue(adr('G1'))).toBeCloseTo(1.01) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-1.01) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(-1.0000001) - expect(engine.getCellValue(adr('C2'))).toBeCloseTo(-1.1) - expect(engine.getCellValue(adr('D2'))).toBeCloseTo(-1.1) - expect(engine.getCellValue(adr('E2'))).toBeCloseTo(-125.056) - expect(engine.getCellValue(adr('F2'))).toBeCloseTo(-5.1) - expect(engine.getCellValue(adr('G2'))).toBeCloseTo(-1.01) - }) -}) diff --git a/test/unit/interpreter/function-edate.spec.ts b/test/unit/interpreter/function-edate.spec.ts deleted file mode 100644 index 60fd5b12d6..0000000000 --- a/test/unit/interpreter/function-edate.spec.ts +++ /dev/null @@ -1,136 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectCellValueToEqualDate} from '../testUtils' - -describe('Function EDATE', () => { - it('validate arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['=EDATE("foo", 0)'], - ['=EDATE(A1, "bar")'], - ['=EDATE(A1)'], - ['=EDATE(A1, "bar", "baz")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 10)'], - ['=EDATE(A1, 0)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '10/03/2019') - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_DATE) - }) - - it('works for exact end of month', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['=EDATE(A1, 0)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/03/2019') - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 7, 31)'], - ['=EDATE(A1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/08/2019') - }) - - it('should return NUMBER_DATE', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 7, 31)'], - ['=EDATE(A1, 1)'], - ]) - - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_DATE) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 8, 31)'], - ['=EDATE(A1, -1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/07/2019') - }) - - it('works when next date will have more days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 6, 30)'], - ['=EDATE(A1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '30/07/2019') - }) - - it('works when next date will have less days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 1, 31)'], - ['=EDATE(A1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '28/02/2019') - }) - - it('works when previous date will have more days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 2, 28)'], - ['=EDATE(A1, -1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '28/01/2019') - }) - - it('works when previous date will have less days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['=EDATE(A1, -1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '28/02/2019') - }) - - it('use number coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=EDATE(TRUE(), 1)'], - ['=EDATE(1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A1'), '31/01/1900') - expectCellValueToEqualDate(engine, adr('A2'), '31/01/1900') - }) - - it('use number coercion for 2nd argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['="1"', '=EDATE(A1, A2)'], - ['=TRUE()', '=EDATE(A1, A3)'], - ]) - - expectCellValueToEqualDate(engine, adr('B2'), '30/04/2019') - expectCellValueToEqualDate(engine, adr('B3'), '30/04/2019') - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=EDATE(4/0, 0)'], - ['=EDATE(0, 4/0)'], - ['=EDATE(4/0, FOOBAR())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-effect.spec.ts b/test/unit/interpreter/function-effect.spec.ts deleted file mode 100644 index ecd4fde353..0000000000 --- a/test/unit/interpreter/function-effect.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function EFFECT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=EFFECT(1)', '=EFFECT(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=EFFECT(2%, 1)', '=EFFECT(2%, 2)', '=EFFECT(2%, 2.9)', '=EFFECT(2%, 24)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.02, 9) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.0201, 9) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(0.0201, 9) - expect(engine.getCellValue(adr('D1'))).toBeCloseTo(0.0201928431045086, 9) - }) -}) diff --git a/test/unit/interpreter/function-eomonth.spec.ts b/test/unit/interpreter/function-eomonth.spec.ts deleted file mode 100644 index 5c92ea2aa8..0000000000 --- a/test/unit/interpreter/function-eomonth.spec.ts +++ /dev/null @@ -1,154 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectCellValueToEqualDate} from '../testUtils' - -describe('Function EOMONTH', () => { - it('validate arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['=EOMONTH("foo", 0)'], - ['=EOMONTH(A1, "bar")'], - ['=EOMONTH(A1)'], - ['=EOMONTH(A1, "bar", "baz")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return NUMBER_DATE', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 7, 31)'], - ['=EOMONTH(A1, 1)'], - ]) - - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_DATE) - }) - - it('works for 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 10)'], - ['=EOMONTH(A1, 0)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/03/2019') - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_DATE) - }) - - it('works for exact end of month', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['=EOMONTH(A1, 0)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/03/2019') - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 7, 31)'], - ['=EOMONTH(A1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/08/2019') - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 8, 31)'], - ['=EOMONTH(A1, -1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/07/2019') - }) - - it('works when next date will have more days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 6, 30)'], - ['=EOMONTH(A1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/07/2019') - }) - - it('works when next date will have less days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 1, 31)'], - ['=EOMONTH(A1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '28/02/2019') - }) - - it('works when previous date will have more days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 2, 28)'], - ['=EOMONTH(A1, -1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '31/01/2019') - }) - - it('works when previous date will have less days', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['=EOMONTH(A1, -1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '28/02/2019') - }) - - it('works for leap years', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2020, 2, 28)'], - ['=EOMONTH(A1, 0)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '29/02/2020') - }) - - it('works for non-leap years', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 2, 28)'], - ['=EOMONTH(A1, 0)'], - ]) - - expectCellValueToEqualDate(engine, adr('A2'), '28/02/2019') - }) - - it('use number coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=EOMONTH(TRUE(), 1)'], - ['=EOMONTH(1, 1)'], - ]) - - expectCellValueToEqualDate(engine, adr('A1'), '31/01/1900') - expectCellValueToEqualDate(engine, adr('A2'), '31/01/1900') - }) - - it('use number coercion for 2nd argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(2019, 3, 31)'], - ['="1"', '=EOMONTH(A1, A2)'], - ['=TRUE()', '=EOMONTH(A1, A3)'], - ]) - - expectCellValueToEqualDate(engine, adr('B2'), '30/04/2019') - expectCellValueToEqualDate(engine, adr('B3'), '30/04/2019') - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=EOMONTH(4/0, 0)'], - ['=EOMONTH(0, 4/0)'], - ['=EOMONTH(4/0, FOOBAR())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-erf.spec.ts b/test/unit/interpreter/function-erf.spec.ts deleted file mode 100644 index 9ef083c227..0000000000 --- a/test/unit/interpreter/function-erf.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ERF', () => { - - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERF()'], - ['=ERF(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERF("foo")'], - ['=ERF(1, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work for single argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERF(0)'], - ['=ERF(1)'], - ['=ERF(3.14)'], - ['=ERF(-2.56)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.9999910304344467, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(-0.999705836979508, 6) - }) - - it('should work with second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERF(-2.3, -0.7)'], - ['=ERF(-2.3, 2)'], - ['=ERF(5.6, -3.1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.32105562956522493, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.9941790884215962, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-1.9999883513426304, 6) - }) -}) diff --git a/test/unit/interpreter/function-erfc.spec.ts b/test/unit/interpreter/function-erfc.spec.ts deleted file mode 100644 index c3beafce27..0000000000 --- a/test/unit/interpreter/function-erfc.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ERFC', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERFC()'], - ['=ERFC(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERFC("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERFC(0)'], - ['=ERFC(2)'], - ['=ERFC(0.5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.004677734981047288, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.4795001221869535, 6) - }) - - it('should work for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ERFC(-10.123)'], - ['=ERFC(-14.8)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(2) - expect(engine.getCellValue(adr('A2'))).toBe(2) - }) -}) diff --git a/test/unit/interpreter/function-even.spec.ts b/test/unit/interpreter/function-even.spec.ts deleted file mode 100644 index d81a98f51d..0000000000 --- a/test/unit/interpreter/function-even.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function EVEN', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=EVEN()', '=EVEN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=EVEN(0.3)', '=EVEN(1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(2) - expect(engine.getCellValue(adr('B1'))).toBe(2) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=EVEN(-0.3)', '=EVEN(-1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-2) - expect(engine.getCellValue(adr('B1'))).toBe(-2) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=EVEN("42.3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(44) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=EVEN(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-exact.spec.ts b/test/unit/interpreter/function-exact.spec.ts deleted file mode 100644 index 27fd373d6e..0000000000 --- a/test/unit/interpreter/function-exact.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function EXACT', () => { - it('should take two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXACT("foo")'], - ['=EXACT("foo", "bar", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should compare strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXACT(B1, C1)', '', ''], - ['=EXACT(B2, C2)', 'foo', 'foo'], - ['=EXACT(B3, C3)', 'foo', 'fo'], - ['=EXACT(B4, C4)', 'foo', 'bar'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toBe(false) - expect(engine.getCellValue(adr('A4'))).toBe(false) - }) - - it('should be case/accent sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXACT(B1, C1)', 'foo', 'FOO'], - ['=EXACT(B2, C2)', 'foo', 'fóó'], - ], {caseSensitive: false}) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('A2'))).toBe(false) - }) - - it('should be case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXACT(B1, C1)', 'foo', 'Foo'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - }) - - it('should coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXACT(,)'], - ['=EXACT(B2, "0")', 0], - ['=EXACT(B3, "")', null], - ['=EXACT(B4, "TRUE")', '=TRUE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toBe(true) - expect(engine.getCellValue(adr('A4'))).toBe(true) - }) - - it('should return error for range', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXACT("foo",B1:C1)'], - ['=EXACT(B1:C1,"foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-exp.spec.ts b/test/unit/interpreter/function-exp.spec.ts deleted file mode 100644 index 5fdf8bd0dd..0000000000 --- a/test/unit/interpreter/function-exp.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function EXP', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXP(0)', '=EXP(2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(7.38905609893065) - }) - - it('given wrong argument type', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXP("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="2"', '=EXP(A1)'], - ['=FALSE()', '=EXP(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(7.38905609893065) - expect(engine.getCellValue(adr('B2'))).toEqual(1) - }) - - it('given wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXP()'], - ['=EXP(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXP(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-expon.dist.spec.ts b/test/unit/interpreter/function-expon.dist.spec.ts deleted file mode 100644 index c14c4ebb16..0000000000 --- a/test/unit/interpreter/function-expon.dist.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function EXPON.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXPON.DIST(1, 2)'], - ['=EXPON.DIST(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXPON.DIST("foo", 2, TRUE())'], - ['=EXPON.DIST(1, "baz", TRUE())'], - ['=EXPON.DIST(1, 2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXPON.DIST(1, 1, TRUE())'], - ['=EXPON.DIST(3, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.632120558828558, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.997521247823334, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXPON.DIST(1, 1, FALSE())'], - ['=EXPON.DIST(3, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.367879441171442, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.00495750435333272, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=EXPON.DIST(0, 1, FALSE())'], - ['=EXPON.DIST(-0.00001, 1, FALSE())'], - ['=EXPON.DIST(1, 0, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-f.dist.rt.spec.ts b/test/unit/interpreter/function-f.dist.rt.spec.ts deleted file mode 100644 index 68d6fc38fa..0000000000 --- a/test/unit/interpreter/function-f.dist.rt.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function F.DIST.RT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST.RT(1, 2)'], - ['=F.DIST.RT(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST.RT("foo", 2, 3)'], - ['=F.DIST.RT(1, "baz", 3)'], - ['=F.DIST.RT(1, 2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST.RT(1, 1, 1)'], - ['=F.DIST.RT(3, 2, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.25, 6) - }) - - it('truncates second and third args', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST.RT(1, 1.9, 1)'], - ['=F.DIST.RT(3, 2, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.25, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST.RT(0, 1, 1)'], - ['=F.DIST.RT(-0.001, 1, 1)'], - ['=F.DIST.RT(0, 0.999, 1)'], - ['=F.DIST.RT(0, 1, 0.999)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-f.dist.spec.ts b/test/unit/interpreter/function-f.dist.spec.ts deleted file mode 100644 index 1122561bdd..0000000000 --- a/test/unit/interpreter/function-f.dist.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function F.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST(1, 2, 3)'], - ['=F.DIST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST("foo", 2, 3, TRUE())'], - ['=F.DIST(1, "baz", 3, TRUE())'], - ['=F.DIST(1, 2, "abcd", TRUE())'], - ['=F.DIST(1, 2, 3, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST(1, 1, 1, TRUE())'], - ['=F.DIST(3, 2, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.75, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST(1, 1, 1, FALSE())'], - ['=F.DIST(3, 2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.159154942198517, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0625, 6) - }) - - it('truncates second and third arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST(1, 1.9, 1, FALSE())'], - ['=F.DIST(3, 2, 2.9, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.159154942198517, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0625, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.DIST(0, 1, 1, FALSE())'], - ['=F.DIST(-0.001, 1, 1, FALSE())'], - ['=F.DIST(0, 0.999, 1, FALSE())'], - ['=F.DIST(0, 1, 0.999, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-f.inv.rt.spec.ts b/test/unit/interpreter/function-f.inv.rt.spec.ts deleted file mode 100644 index 8e82250b0d..0000000000 --- a/test/unit/interpreter/function-f.inv.rt.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function F.INV.RT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV.RT(1, 2)'], - ['=F.INV.RT(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV.RT("foo", 2, 3)'], - ['=F.INV.RT(1, "baz", 3)'], - ['=F.INV.RT(1, 2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV.RT(0.1, 1, 1)'], - ['=F.INV.RT(0.9, 2, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(39.8634581890474, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.111111111111111, 6) - }) - - it('truncates second and third arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV.RT(0.1, 1.9, 1)'], - ['=F.INV.RT(0.9, 2, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(39.8634581890474, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.111111111111111, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV.RT(0.5, 0.999, 1)'], - ['=F.INV.RT(0.5, 1, 0.999)'], - ['=F.INV.RT(-0.0001, 2, 1)'], - ['=F.INV.RT(1.0001, 2, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-f.inv.spec.ts b/test/unit/interpreter/function-f.inv.spec.ts deleted file mode 100644 index 846421eb60..0000000000 --- a/test/unit/interpreter/function-f.inv.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function F.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV(1, 2)'], - ['=F.INV(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV("foo", 2, 3)'], - ['=F.INV(1, "baz", 3)'], - ['=F.INV(1, 2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV(0.1, 1, 1)'], - ['=F.INV(0.9, 2, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0250856309369253, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(9, 6) - }) - - it('truncates second and third arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV(0.1, 1.9, 1)'], - ['=F.INV(0.9, 2, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0250856309369253, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(9, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.INV(0.5, 0.999, 1)'], - ['=F.INV(0.5, 1, 0.999)'], - ['=F.INV(-0.0001, 2, 1)'], - ['=F.INV(1.0001, 2, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-f.test.spec.ts b/test/unit/interpreter/function-f.test.spec.ts deleted file mode 100644 index 4bdda704c9..0000000000 --- a/test/unit/interpreter/function-f.test.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('F.TEST', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.TEST(1)'], - ['=F.TEST(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['2', '5'], - ['=F.TEST(A1:A2, B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.2513318328, 6) - }) - - it('works for uneven ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['2', '3'], - [null, '1'], - ['=F.TEST(A1:A2, B1:B3)'] - ]) - - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(0.794719414238988, 6) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - ['5', '3'], - [null, '6'], - [true, false], - ['8'], - ['=F.TEST(A1:A4, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(1, 6) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=4/0', '50'], - ['3', '30'], - ['=F.TEST(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.TEST(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('error when 0 variance', () => { - const engine = HyperFormula.buildFromArray([ - ['=F.TEST(A2:C2, A3:C3)'], - [1, 1, 1], - [0, 1, 0], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-fact.spec.ts b/test/unit/interpreter/function-fact.spec.ts deleted file mode 100644 index fe4da366e5..0000000000 --- a/test/unit/interpreter/function-fact.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FACT', () => { - it('checks number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACT()', '=FACT(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACT(0)'], - ['=FACT(1)'], - ['=FACT(10)'], - ['=FACT(170)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(1) - expect(engine.getCellValue(adr('A3'))).toBe(3628800) - expect(engine.getCellValue(adr('A4')) as number / 7.257415615307999e+306).toBeCloseTo(1, 6) - }) - - it('rounds argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACT(0.9)'], - ['=FACT(1.1)'], - ['=FACT(10.42)'], - ['=FACT(169.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(1) - expect(engine.getCellValue(adr('A3'))).toBe(3628800) - expect(engine.getCellValue(adr('A4')) as number / 4.2690680090046997e+304).toBeCloseTo(1, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACT(-1)'], - ['=FACT(171)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('uses coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACT("0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACT(NA())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-factdouble.spec.ts b/test/unit/interpreter/function-factdouble.spec.ts deleted file mode 100644 index c612f569d4..0000000000 --- a/test/unit/interpreter/function-factdouble.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FACTDOUBLE', () => { - it('checks number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACTDOUBLE()', '=FACTDOUBLE(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACTDOUBLE(0)'], - ['=FACTDOUBLE(1)'], - ['=FACTDOUBLE(10)'], - ['=FACTDOUBLE(288)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(1) - expect(engine.getCellValue(adr('A3'))).toBe(3840) - expect(engine.getCellValue(adr('A4')) as number / 1.23775688540895e+293).toBeCloseTo(1, 6) - }) - - it('rounds argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACTDOUBLE(0.9)'], - ['=FACTDOUBLE(1.1)'], - ['=FACTDOUBLE(10.42)'], - ['=FACTDOUBLE(287.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(1) - expect(engine.getCellValue(adr('A3'))).toBe(3840) - expect(engine.getCellValue(adr('A4')) as number / 5.81436347598024e+291).toBeCloseTo(1, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACTDOUBLE(-1)'], - ['=FACTDOUBLE(289)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('uses coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACTDOUBLE("0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=FACTDOUBLE(NA())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-false.spec.ts b/test/unit/interpreter/function-false.spec.ts deleted file mode 100644 index ad25775244..0000000000 --- a/test/unit/interpreter/function-false.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FALSE', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([['=FALSE()']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('is 0-arity', () => { - const engine = HyperFormula.buildFromArray([['=FALSE(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) -}) diff --git a/test/unit/interpreter/function-filter.spec.ts b/test/unit/interpreter/function-filter.spec.ts deleted file mode 100644 index 8306f072b7..0000000000 --- a/test/unit/interpreter/function-filter.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import {ErrorType, HyperFormula, Sheets} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FILTER', () => { - it('should return an error for 2-dimensional arrays', () => { - const engine = HyperFormula.buildFromArray([['=FILTER(D2:E3, D2:E3)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongDimension)) - }) - - it('should return an error if arrays have different dimensions', () => { - const engine = HyperFormula.buildFromArray([['=FILTER(D2:D3, D2:D3, D2:D4)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('should return an error if param1 is not a range', () => { - const engine = HyperFormula.buildFromArray([['=FILTER(1, FALSE())']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EmptyRange)) - }) - - it('should filter a horizontal range if one condition is passed', () => { - const engine = HyperFormula.buildFromArray([['=FILTER(A2:C2,A3:C3)'], [1, 2, 3], [true, false, true]]) - - expect(engine.getSheetValues(0)).toEqual([[1, 3], [1, 2, 3], [true, false, true]]) - }) - - it('should filter a horizontal range if two conditions are passed', () => { - const engine = HyperFormula.buildFromArray([['=FILTER(A2:C2,A3:C3,A4:C4)'], [1, 2, 3], [true, false, true], [true, true, false]]) - - expect(engine.getSheetValues(0)).toEqual([[1], [1, 2, 3], [true, false, true], [true, true, false]]) - }) - - it('should filter a vertical range', () => { - const engine = HyperFormula.buildFromArray([['=FILTER(B1:B3,C1:C3)', 1, true], [undefined, 2, false], [undefined, 3, true]]) - - expect(engine.getSheetValues(0)).toEqual([[1, 1, true], [3, 2, false], [null, 3, true]]) - }) - - it('should enable array arithmetic implicitly', () => { - const engine = HyperFormula.buildFromArray([['=FILTER(2*A2:C2,A3:C3)'], [1, 2, 3], [true, true, true]]) - - expect(engine.getSheetValues(0)).toEqual([[2, 4, 6], [1, 2, 3], [true, true, true]]) - }) - - it('should allow to construct a multidimensional array by calling filter for each column separately', () => { - const sheets: Sheets = { - Data: [ - ['a', 1, 42], - ['b', 2, 42], - ['a', 3, 42], - ['b', 4, 42], - ], - Result: [[ - '=FILTER(Data!A1:A4, Data!A1:A4="a")', - '=FILTER(Data!B1:B4, Data!A1:A4="a")', - '=FILTER(Data!C1:C4, Data!A1:A4="a")', - ]], - } - - const engine = HyperFormula.buildFromSheets(sheets) - const result = engine.getSheetValues(engine.getSheetId('Result') as number) - - expect(result).toEqual([ - ['a', 1, 42], - ['a', 3, 42], - ]) - }) -}) diff --git a/test/unit/interpreter/function-find.spec.ts b/test/unit/interpreter/function-find.spec.ts deleted file mode 100644 index 025a066add..0000000000 --- a/test/unit/interpreter/function-find.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FIND', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=FIND()'], - ['=FIND("foo")'], - ['=FIND("foo", 1, 2, 3)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return VALUE when wrong type of third parameter', () => { - const engine = HyperFormula.buildFromArray([ - ['=FIND("foo", "bar", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return VALUE if third parameter is not between 1 and text length', () => { - const engine = HyperFormula.buildFromArray([ - ['=FIND("foo", "bar", 0)'], - ['=FIND("foo", "bar", -1)'], - ['=FIND("foo", "bar", 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IndexBounds)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IndexBounds)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IndexBounds)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=FIND("f", "foo")'], - ['=FIND("o", "foo")'], - ['=FIND("o", "foo", 3)'], - ['=FIND("g", "foo")'], - ['=FIND("?o", "?o")'], - ['=FIND("?o", "oo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - }) - - it('should be case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['=FIND("R", "bar")'], - ['=FIND("r", "bar")'], - ['=FIND("r", "baR")'], - ['=FIND("R", "baR")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=FIND(1, 1, 1)'], - ['=FIND(0, 5+5)'], - ['=FIND("U", TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) -}) diff --git a/test/unit/interpreter/function-fisher.spec.ts b/test/unit/interpreter/function-fisher.spec.ts deleted file mode 100644 index 0db60ffd21..0000000000 --- a/test/unit/interpreter/function-fisher.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FISHER', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FISHER()'], - ['=FISHER(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=FISHER("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=FISHER(0)'], - ['=FISHER(0.5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.549306144334055, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=FISHER(-1)'], - ['=FISHER(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-fisherinv.spec.ts b/test/unit/interpreter/function-fisherinv.spec.ts deleted file mode 100644 index 7346e19420..0000000000 --- a/test/unit/interpreter/function-fisherinv.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FISHERINV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FISHERINV()'], - ['=FISHERINV(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=FISHERINV("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=FISHERINV(0)'], - ['=FISHERINV(0.5)'], - ['=FISHERINV(-5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.46211715726001, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.999909204262595, 6) - }) -}) diff --git a/test/unit/interpreter/function-floor.math.spec.ts b/test/unit/interpreter/function-floor.math.spec.ts deleted file mode 100644 index 24615f64d7..0000000000 --- a/test/unit/interpreter/function-floor.math.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FLOOR.MATH', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.MATH()'], - ['=FLOOR.MATH(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.MATH("foo")'], - ['=FLOOR.MATH(1, "bar")'], - ['=FLOOR.MATH(1, 2, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.MATH(4.43, 0.3)'], - ['=FLOOR.MATH(4.43, 0.6)'], - ['=FLOOR.MATH(4.43, 2)'], - ['=FLOOR.MATH(4.43)'], - ['=FLOOR.MATH(-4.43)'], - ['=FLOOR.MATH(-3.14, -1.8)'], - ['=FLOOR.MATH(-3.14, 0)'], - ['=FLOOR.MATH(3.14, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4.2) - expect(engine.getCellValue(adr('A2'))).toEqual(4.2) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(engine.getCellValue(adr('A5'))).toEqual(-5) - expect(engine.getCellValue(adr('A6'))).toEqual(-3.6) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - expect(engine.getCellValue(adr('A8'))).toEqual(0) - }) - - it('should work with mode for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.MATH(-11, -2)'], - ['=FLOOR.MATH(-11, -2, 0)'], - ['=FLOOR.MATH(-11, -2, 1)'], - ['=FLOOR.MATH(-11, 0, 1)'], - ['=FLOOR.MATH(-11, 0, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-12) - expect(engine.getCellValue(adr('A2'))).toEqual(-12) - expect(engine.getCellValue(adr('A3'))).toEqual(-10) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - }) - - it('negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.MATH(11, 2, 0)'], - ['=FLOOR.MATH(-11, 2, 0)'], - ['=FLOOR.MATH(11, -2, 0)'], - ['=FLOOR.MATH(-11, -2, 0)'], - ['=FLOOR.MATH(11, 2, 1)'], - ['=FLOOR.MATH(-11, 2, 1)'], - ['=FLOOR.MATH(11, -2, 1)'], - ['=FLOOR.MATH(-11, -2, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(10) - expect(engine.getCellValue(adr('A2'))).toEqual(-12) - expect(engine.getCellValue(adr('A3'))).toEqual(10) - expect(engine.getCellValue(adr('A4'))).toEqual(-12) - expect(engine.getCellValue(adr('A5'))).toEqual(10) - expect(engine.getCellValue(adr('A6'))).toEqual(-10) - expect(engine.getCellValue(adr('A7'))).toEqual(10) - expect(engine.getCellValue(adr('A8'))).toEqual(-10) - }) -}) diff --git a/test/unit/interpreter/function-floor.precise.spec.ts b/test/unit/interpreter/function-floor.precise.spec.ts deleted file mode 100644 index e83b106c66..0000000000 --- a/test/unit/interpreter/function-floor.precise.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FLOOR.PRECISE', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.PRECISE()'], - ['=FLOOR.PRECISE(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.PRECISE(1, "bar")'], - ['=FLOOR.PRECISE("bar", 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.PRECISE(4.43, 0.3)'], - ['=FLOOR.PRECISE(4.43, 0.6)'], - ['=FLOOR.PRECISE(4.43, 2)'], - ['=FLOOR.PRECISE(-3.14, -1.8)'], - ['=FLOOR.PRECISE(-3.14, 0)'], - ['=FLOOR.PRECISE(3.14, 0)'], - ['=FLOOR.PRECISE(3.14)'], - ['=FLOOR.PRECISE(-3.14)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4.2) - expect(engine.getCellValue(adr('A2'))).toEqual(4.2) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(-3.6) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(0) - expect(engine.getCellValue(adr('A7'))).toEqual(3) - expect(engine.getCellValue(adr('A8'))).toEqual(-4) - }) - - it('negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR.PRECISE(11, 2)'], - ['=FLOOR.PRECISE(-11, 2)'], - ['=FLOOR.PRECISE(11, -2)'], - ['=FLOOR.PRECISE(-11, -2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(10) - expect(engine.getCellValue(adr('A2'))).toEqual(-12) - expect(engine.getCellValue(adr('A3'))).toEqual(10) - expect(engine.getCellValue(adr('A4'))).toEqual(-12) - }) -}) diff --git a/test/unit/interpreter/function-floor.spec.ts b/test/unit/interpreter/function-floor.spec.ts deleted file mode 100644 index 6001387254..0000000000 --- a/test/unit/interpreter/function-floor.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FLOOR', () => { - /*Inconsistent with ODFF standard.*/ - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR(1)'], - ['=FLOOR(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR(1, "bar")'], - ['=FLOOR("bar", 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR(4.43, 0.3)'], - ['=FLOOR(4.43, 0.6)'], - ['=FLOOR(4.43, 2)'], - ['=FLOOR(-3.14, -1.8)'], - ['=FLOOR(-3.14, 0)'], - ['=FLOOR(3.14, 0)'], - ['=FLOOR(0, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4.2) - expect(engine.getCellValue(adr('A2'))).toEqual(4.2) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(-1.8) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - }) - - /*Inconsistent with ODFF standard.*/ - it('negative values', () => { - const engine = HyperFormula.buildFromArray([ - ['=FLOOR(11, 2)'], - ['=FLOOR(-11, 2)'], - ['=FLOOR(11, -2)'], - ['=FLOOR(-11, -2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(10) - expect(engine.getCellValue(adr('A2'))).toEqual(-12) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.DistinctSigns)) - expect(engine.getCellValue(adr('A4'))).toEqual(-10) - }) -}) diff --git a/test/unit/interpreter/function-formulatext.spec.ts b/test/unit/interpreter/function-formulatext.spec.ts deleted file mode 100644 index a8e2016336..0000000000 --- a/test/unit/interpreter/function-formulatext.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FORMULATEXT', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=FORMULATEXT()'], - ['=FORMULATEXT(B2, B3)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return N/A for wrong types of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FORMULATEXT(1)'], - ['=FORMULATEXT("foo")'], - ['=FORMULATEXT(SUM(1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - }) - - it('should propagate expression error', () => { - const engine = HyperFormula.buildFromArray([ - ['=FORMULATEXT(1/0)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return text of a formula evaluating to error', () => { - const engine = HyperFormula.buildFromArray([ - ['=1/0', '=FORMULATEXT(A1)'] - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual('=1/0') - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, 2)', '=FORMULATEXT(A1)'] - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual('=SUM(1, 2)') - }) - - it('should return formula of a left corner cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, 2)', '=FORMULATEXT(A1:A2)'] - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual('=SUM(1, 2)') - }) - - it('should return REF when', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1, 2)'] - ]) - engine.addSheet('Sheet2') - engine.setCellContents(adr('B1'), '=FORMULATEXT(Sheet1!A1:Sheet2!A2)') - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.CellRefExpected)) - }) - - it('should work for unparsed formula', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1,', '=FORMULATEXT(A1)'] - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual('=SUM(1,') - }) - - it('should return itself', () => { - const engine = HyperFormula.buildFromArray([ - ['=FORMULATEXT(A1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('=FORMULATEXT(A1)') - }) - - it('should be dependent on sheet structure changes', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(A2)', '=FORMULATEXT(A1)'], - [1] - ]) - - engine.addRows(0, [1, 1]) - - expect(engine.getCellFormula(adr('A1'))).toEqual('=SUM(A3)') - expect(engine.getCellValue(adr('B1'))).toEqual('=SUM(A3)') - }) -}) diff --git a/test/unit/interpreter/function-fv.spec.ts b/test/unit/interpreter/function-fv.spec.ts deleted file mode 100644 index 97b31f58bf..0000000000 --- a/test/unit/interpreter/function-fv.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FV', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FV(1, 1)', '=FV(1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=FV(2%, 24, 100)', '=FV(2%, 24, 100, 400)', '=FV(2%, 24, 100, 400, 1)'], - ['=FV(0, 24, 100)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-3042.18624737613) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-3685.56114716622) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(-3746.40487211374) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-2400) - }) -}) diff --git a/test/unit/interpreter/function-fvschedule.spec.ts b/test/unit/interpreter/function-fvschedule.spec.ts deleted file mode 100644 index 548f8d3e79..0000000000 --- a/test/unit/interpreter/function-fvschedule.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function FVSCHEDULE', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=FVSCHEDULE(1)', '=FVSCHEDULE(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=FVSCHEDULE(1, 1)'], - ['=FVSCHEDULE(2, B2:D2)', 1, 1, null], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('A2'))).toEqual(8) - }) - - it('should return proper error', () => { - const engine = HyperFormula.buildFromArray([ - ['=FVSCHEDULE(2, B1:C1)', '\'1', true], - ['=FVSCHEDULE(1, B2:C2)', 'abcd', '=NA()'], - ['=FVSCHEDULE(1, B3)', 'abcd'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberExpected)) - }) -}) diff --git a/test/unit/interpreter/function-gamma.dist.spec.ts b/test/unit/interpreter/function-gamma.dist.spec.ts deleted file mode 100644 index c411fd7046..0000000000 --- a/test/unit/interpreter/function-gamma.dist.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function GAMMA.DIST', () => { - - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.DIST(1, 2, 3)'], - ['=GAMMA.DIST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.DIST("foo", 2, 3, TRUE())'], - ['=GAMMA.DIST(1, "baz", 3, TRUE())'], - ['=GAMMA.DIST(1, 2, "baz", TRUE())'], - ['=GAMMA.DIST(1, 2, 3, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.DIST(1, 1, 2, TRUE())'], - ['=GAMMA.DIST(3, 2, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.393469340287367, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.173358532703224, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.DIST(1, 1, 2, FALSE())'], - ['=GAMMA.DIST(3, 2, 4, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.303265329856317, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0885687286389403, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.DIST(0, 1, 1, FALSE())'], - ['=GAMMA.DIST(-0.00001, 1, 1, FALSE())'], - ['=GAMMA.DIST(1, 0, 1, FALSE())'], - ['=GAMMA.DIST(1, 1, 0, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-gamma.inv.spec.ts b/test/unit/interpreter/function-gamma.inv.spec.ts deleted file mode 100644 index 735c7a977e..0000000000 --- a/test/unit/interpreter/function-gamma.inv.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function GAMMA.INV', () => { - - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.INV(1, 2)'], - ['=GAMMA.INV(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.INV("foo", 2, 3)'], - ['=GAMMA.INV(0.5, "baz", 3)'], - ['=GAMMA.INV(0.5, 2, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.INV(0.5, 1, 1)'], - ['=GAMMA.INV(0.9, 2, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.693147180559945, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(15.5588806794697, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA.INV(0, 1, 1)'], - ['=GAMMA.INV(-0.00001, 1, 1)'], - ['=GAMMA.INV(1, 1, 1)'], - ['=GAMMA.INV(0, 0, 1)'], - ['=GAMMA.INV(0, 1, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-gamma.spec.ts b/test/unit/interpreter/function-gamma.spec.ts deleted file mode 100644 index bd5e68c001..0000000000 --- a/test/unit/interpreter/function-gamma.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function GAMMA', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA()'], - ['=GAMMA(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA(1)'], - ['=GAMMA(0.5)'], - ['=GAMMA(10.5)'], - ['=GAMMA(-2.5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.77245385588014, 6) - expect(engine.getCellValue(adr('A3')) as number / 1133278.39212948).toBeCloseTo(1, 6) - //product #1 returns NUM for the following test - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(-0.94530871782981, 6) - }) - - it('should return nan', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMA(0)'], - ['=GAMMA(-1)'], - ['=GAMMA(180)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) -}) diff --git a/test/unit/interpreter/function-gammaln.spec.ts b/test/unit/interpreter/function-gammaln.spec.ts deleted file mode 100644 index ea23c1bd7c..0000000000 --- a/test/unit/interpreter/function-gammaln.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function GAMMALN', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMALN()'], - ['=GAMMALN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMALN("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMALN(0.1)'], - ['=GAMMALN(1)'], - ['=GAMMALN(10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.25271265173425, 6) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(12.801827480082, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAMMALN(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-gauss.spec.ts b/test/unit/interpreter/function-gauss.spec.ts deleted file mode 100644 index db87d00733..0000000000 --- a/test/unit/interpreter/function-gauss.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function GAUSS', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAUSS()'], - ['=GAUSS(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAUSS("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=GAUSS(-10)'], - ['=GAUSS(0)'], - ['=GAUSS(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-0.5, 6) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.341344746068543, 6) - }) -}) diff --git a/test/unit/interpreter/function-gcd.spec.ts b/test/unit/interpreter/function-gcd.spec.ts deleted file mode 100644 index f8f32f34ae..0000000000 --- a/test/unit/interpreter/function-gcd.spec.ts +++ /dev/null @@ -1,117 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function GCD', () => { - it('checks required number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('computes correct answer for two args', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(2*3*5, 3*5*7)', '=GCD(0, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3 * 5) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('computes correct answer for more than two args', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(2*3*5, 3*5*7, 2*5*7)', '=GCD(100, 101, 102, 103, 104)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(5) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('works with zeroes', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(2*3*5, 3*5*7, 2*5*7, 0, 0, 0)', '=GCD(0, 0, 100, 101, 102, 103, 104, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(5) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('accepts single arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(1)', '=GCD(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(0) - }) - - it('coerces to number', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD("2",4)'], - ['=GCD(B2:C2)', '\'2', 4], - ['=GCD(TRUE(), 4)'], - ['=GCD(B4:C4)', true, 4], - ['=GCD(,4)'], - ['=GCD(B6:C6)', null, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(2) - expect(engine.getCellValue(adr('A2'))).toBe(2) - expect(engine.getCellValue(adr('A3'))).toBe(1) - expect(engine.getCellValue(adr('A4'))).toBe(1) - expect(engine.getCellValue(adr('A5'))).toBe(4) - expect(engine.getCellValue(adr('A6'))).toBe(4) - }) - - it('ignores non-coercible values', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(B1:C1)', 'abcd', 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(4) - }) - - it('throws error for non-coercible values', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD("abcd", 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('handles overflow', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(1000000000000000000.0)'], - ]) - - //inconsistency with product #1 - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(-1, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('truncates numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(B1:C1)', 5.5, 10], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(5) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=GCD(NA(),4)'], - ['=GCD(B2:C2)', '=NA()', 4], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-geomean.spec.ts b/test/unit/interpreter/function-geomean.spec.ts deleted file mode 100644 index c0fb35e9c6..0000000000 --- a/test/unit/interpreter/function-geomean.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function GEOMEAN', () => { - it('single number', () => { - const engine = HyperFormula.buildFromArray([ - ['=GEOMEAN(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('two numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=GEOMEAN(1, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('more numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=GEOMEAN(8, 1, 2, 4, 16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('validates input', () => { - const engine = HyperFormula.buildFromArray([ - ['=GEOMEAN(8, 0, 2, 4, 16)'], - ['=GEOMEAN(8, -1, -2, 4, 16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '9', '3'], - ['=GEOMEAN(A1:C1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('propagates error from regular argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=GEOMEAN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('propagates first error from range argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=FOO(', '=GEOMEAN(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('returns error for empty ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=GEOMEAN(A2:A3)'], - [null], - [null], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.OneValue)) - }) - - /** - * product #1 does not coerce the input - */ - it('does coercions of nonnumeric explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=GEOMEAN(TRUE(),"4")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('ignores nonnumeric values in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=GEOMEAN(A2:D2)'], - [1, 1, false, null, '\'0'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) -}) diff --git a/test/unit/interpreter/function-harmean.spec.ts b/test/unit/interpreter/function-harmean.spec.ts deleted file mode 100644 index d8da700cfd..0000000000 --- a/test/unit/interpreter/function-harmean.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HARMEAN', () => { - it('single number', () => { - const engine = HyperFormula.buildFromArray([ - ['=HARMEAN(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('two numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=HARMEAN(1, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1.6) - }) - - it('more numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=HARMEAN(8, 1, 2, 4, 16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.58064516129032, 6) - }) - - it('validates input', () => { - const engine = HyperFormula.buildFromArray([ - ['=HARMEAN(8, 0, 2, 4, 16)'], - ['=HARMEAN(8, -1, -2, 4, 16)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '9', '3'], - ['=HARMEAN(A1:C1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(2.07692307692308, 6) - }) - - it('propagates error from regular argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=HARMEAN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('propagates first error from range argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=FOO(', '=HARMEAN(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('returns error for empty ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=HARMEAN(A2:A3)'], - [null], - [null], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.OneValue)) - }) - - /** - * product #1 does not coerce the input - */ - it('does coercions of nonnumeric explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HARMEAN(TRUE(),"4")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1.6) - }) - - it('ignores nonnumeric values in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=HARMEAN(A2:D2)'], - [1, 1, false, null, '\'0'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) -}) diff --git a/test/unit/interpreter/function-hex2bin.spec.ts b/test/unit/interpreter/function-hex2bin.spec.ts deleted file mode 100644 index aef58abf06..0000000000 --- a/test/unit/interpreter/function-hex2bin.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function HEX2BIN', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-hex arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN("foo")'], - ['=HEX2BIN("G418")'], - ['=HEX2BIN(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN("1")'], - ['=HEX2BIN("F")'], - ['=HEX2BIN("2A")'], - ['=HEX2BIN("1FF")'], - ['=HEX2BIN("FFFFFFFFF6")'], - ['=HEX2BIN("FFFFFFFF9C")'], - ['=HEX2BIN("FFFFFFFE00")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('1111') - expect(engine.getCellValue(adr('A3'))).toEqual('101010') - expect(engine.getCellValue(adr('A4'))).toEqual('111111111') - expect(engine.getCellValue(adr('A5'))).toEqual('1111110110') - expect(engine.getCellValue(adr('A6'))).toEqual('1110011100') - expect(engine.getCellValue(adr('A7'))).toEqual('1000000000') - }) - - it('should work for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN(156)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('101010110') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="12A"'], - ['=HEX2BIN(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('100101010') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN(11)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('result cannot be longer than 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN("200")'], - ['=HEX2BIN("FFFFFFFDFF")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseSmall)) - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN(12, 8)'], - ['=HEX2BIN(3, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00010010') - expect(engine.getCellValue(adr('A2'))).toEqual('0011') - }) - - it('second argument should not affect negative results', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN("FFFFFFFF9C", 1)'], - ['=HEX2BIN("FFFFFFFFF6", 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1110011100') - expect(engine.getCellValue(adr('A2'))).toEqual('1111110110') - }) - - it('should fail if the result is longer than the desired length', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN("100", 2)'], - ['=HEX2BIN("FF", "3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2BIN(2, 0)'], - ['=HEX2BIN(2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-hex2dec.spec.ts b/test/unit/interpreter/function-hex2dec.spec.ts deleted file mode 100644 index a7f5b38660..0000000000 --- a/test/unit/interpreter/function-hex2dec.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function HEX2DEC', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2DEC("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-hex arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2DEC("foo")'], - ['=HEX2DEC("23G")'], - ['=HEX2DEC(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2DEC("1")'], - ['=HEX2DEC("10")'], - ['=HEX2DEC("AD")'], - ['=HEX2DEC("ABBA")'], - ['=HEX2DEC("BA0AB")'], - ['=HEX2DEC("B09D65")'], - ['=HEX2DEC("F1808E4")'], - ['=HEX2DEC("B07D007")'], - ['=HEX2DEC("7FFFFFFFFF")'], - ['=HEX2DEC("F352DEB731")'], - ['=HEX2DEC("FFFFFFFFFF")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(16) - expect(engine.getCellValue(adr('A3'))).toEqual(173) - expect(engine.getCellValue(adr('A4'))).toEqual(43962) - expect(engine.getCellValue(adr('A5'))).toEqual(762027) - expect(engine.getCellValue(adr('A6'))).toEqual(11574629) - expect(engine.getCellValue(adr('A7'))).toEqual(253233380) - expect(engine.getCellValue(adr('A8'))).toEqual(185061383) - expect(engine.getCellValue(adr('A9'))).toBeCloseTo(549755813887, -1) - expect(engine.getCellValue(adr('A10'))).toEqual(-54444247247) - expect(engine.getCellValue(adr('A11'))).toEqual(-1) - }) - - it('should work for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2DEC(456)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1110) - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="1A3"'], - ['=HEX2DEC(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(419) - }) - - it('should return a number', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2DEC("11")'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.NUMBER) - }) - - it('should work only for 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2DEC("1010B040205")'], - ['=HEX2DEC("7777EE70D2")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(513113223378, -1) - }) -}) diff --git a/test/unit/interpreter/function-hex2oct.spec.ts b/test/unit/interpreter/function-hex2oct.spec.ts deleted file mode 100644 index bdc996de27..0000000000 --- a/test/unit/interpreter/function-hex2oct.spec.ts +++ /dev/null @@ -1,137 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function HEX2OCT', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-hex arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT("foo")'], - ['=HEX2OCT("G418")'], - ['=HEX2OCT(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT("1")'], - ['=HEX2OCT("F")'], - ['=HEX2OCT("2A")'], - ['=HEX2OCT("26235")'], - ['=HEX2OCT("1BB95B19")'], - ['=HEX2OCT("CE6D570")'], - ['=HEX2OCT("FFFB4B62A9")'], - ['=HEX2OCT("FFFF439EB2")'], - ['=HEX2OCT("FFFFFFFFFF")'], - ['=HEX2OCT("1FFFFFFF")'], - ['=HEX2OCT("FFE0000000")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('17') - expect(engine.getCellValue(adr('A3'))).toEqual('52') - expect(engine.getCellValue(adr('A4'))).toEqual('461065') - expect(engine.getCellValue(adr('A5'))).toEqual('3356255431') - expect(engine.getCellValue(adr('A6'))).toEqual('1471552560') - expect(engine.getCellValue(adr('A7'))).toEqual('7322661251') - expect(engine.getCellValue(adr('A8'))).toEqual('7720717262') - expect(engine.getCellValue(adr('A9'))).toEqual('7777777777') - expect(engine.getCellValue(adr('A10'))).toEqual('3777777777') - expect(engine.getCellValue(adr('A11'))).toEqual('4000000000') - }) - - it('should work for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT(456)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('2126') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="123"'], - ['=HEX2OCT(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('443') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT(11)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('result cannot be longer than 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT("FFDFFFFFFF")'], - ['=HEX2OCT("3FFFFFFF")'], ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - }) - - it('input cannot have more than 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT("10000000000")'], - - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotHex)) - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT(12, 8)'], - ['=HEX2OCT(3, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00000022') - expect(engine.getCellValue(adr('A2'))).toEqual('0003') - }) - - it('should fail if the result is longer than the desired length', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT(32123, 2)'], - ['=HEX2OCT(433141, "3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - }) - - it('second argument should not affect negative results', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT("FFFB4B62A9", 1)'], - ['=HEX2OCT("FFFF439EB2", 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('7322661251') - expect(engine.getCellValue(adr('A2'))).toEqual('7720717262') - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HEX2OCT(2, 0)'], - ['=HEX2OCT(2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-hfadd.spec.ts b/test/unit/interpreter/function-hfadd.spec.ts deleted file mode 100644 index 1db97d7427..0000000000 --- a/test/unit/interpreter/function-hfadd.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.ADD', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.ADD(1)', '=HF.ADD(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.ADD(2, 3)'], - ['=HF.ADD(1.0000000000001, -1)'], - ['=HF.ADD(1,)'], - ['=HF.ADD(,)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.ADD(TRUE(),B1)'], - ['=HF.ADD("1",)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.ADD("abcd",)'], - ['=HF.ADD(NA(),)'], - ['=HF.ADD(B3:C3,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('passes subtypes', () => { - const engine = HyperFormula.buildFromArray([['=HF.ADD(B1,C1)', '1$', 1]]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - }) -}) diff --git a/test/unit/interpreter/function-hfconcat.spec.ts b/test/unit/interpreter/function-hfconcat.spec.ts deleted file mode 100644 index 59d1f1f87f..0000000000 --- a/test/unit/interpreter/function-hfconcat.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.CONCAT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.CONCAT(1)', '=HF.CONCAT(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.CONCAT("hokuspokus","czarymary")'], - ['=HF.CONCAT(,"a")'], - ['=HF.CONCAT(,)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('hokuspokusczarymary') - expect(engine.getCellValue(adr('A2'))).toEqual('a') - expect(engine.getCellValue(adr('A3'))).toEqual('') - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.CONCAT(TRUE(),B1)'], - ['=HF.CONCAT(1,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('TRUE') - expect(engine.getCellValue(adr('A2'))).toEqual('1') - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.CONCAT(NA(),)'], - ['=HF.CONCAT(B2:C2,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfdivide.spec.ts b/test/unit/interpreter/function-hfdivide.spec.ts deleted file mode 100644 index b21e8787e7..0000000000 --- a/test/unit/interpreter/function-hfdivide.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.DIVIDE', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.DIVIDE(1)', '=HF.DIVIDE(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.DIVIDE(6,4)'], - ['=HF.DIVIDE(,1)'], - ['=HF.DIVIDE(1,)'], - ['=HF.DIVIDE(,)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1.5) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.DIVIDE(TRUE(),1)'], - ['=HF.DIVIDE(B2,1)'], - ['=HF.DIVIDE("1",1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.DIVIDE("abcd",)'], - ['=HF.DIVIDE(NA(),)'], - ['=HF.DIVIDE(B3:C3,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('passes subtypes', () => { - const engine = HyperFormula.buildFromArray([['=HF.DIVIDE(B1,C1)', '1$', 1]]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - }) -}) diff --git a/test/unit/interpreter/function-hfeq.spec.ts b/test/unit/interpreter/function-hfeq.spec.ts deleted file mode 100644 index 8b66a4bc3c..0000000000 --- a/test/unit/interpreter/function-hfeq.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.EQ', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.EQ(1)', '=HF.EQ(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.EQ(1, 0)'], - ['=HF.EQ(1, 1)'], - ['=HF.EQ("1", "0")'], - ['=HF.EQ("1", "1")'], - ['=HF.EQ(TRUE(), FALSE())'], - ['=HF.EQ(TRUE(), TRUE())'], - ['=HF.EQ(,)'], - ['=HF.EQ(1,)'], - ['=HF.EQ("1",)'], - ['=HF.EQ(TRUE(),)'], - ['=HF.EQ("1", 1)'], - ['=HF.EQ(TRUE(), 1)'], - ['=HF.EQ(TRUE(), "1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('A2'))).toEqual(true) - expect(engine.getCellValue(adr('A3'))).toEqual(false) - expect(engine.getCellValue(adr('A4'))).toEqual(true) - expect(engine.getCellValue(adr('A5'))).toEqual(false) - expect(engine.getCellValue(adr('A6'))).toEqual(true) - expect(engine.getCellValue(adr('A7'))).toEqual(true) - expect(engine.getCellValue(adr('A8'))).toEqual(false) - expect(engine.getCellValue(adr('A9'))).toEqual(false) - expect(engine.getCellValue(adr('A10'))).toEqual(false) - expect(engine.getCellValue(adr('A11'))).toEqual(false) - expect(engine.getCellValue(adr('A12'))).toEqual(false) - expect(engine.getCellValue(adr('A13'))).toEqual(false) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.EQ(NA(),)'], - ['=HF.EQ(B2:C2,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfgt.spec.ts b/test/unit/interpreter/function-hfgt.spec.ts deleted file mode 100644 index 5878215571..0000000000 --- a/test/unit/interpreter/function-hfgt.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.GT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.GT(1)', '=HF.GT(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.GT(1, 0)'], - ['=HF.GT(1, 1)'], - ['=HF.GT("1", "0")'], - ['=HF.GT("1", "1")'], - ['=HF.GT(TRUE(), FALSE())'], - ['=HF.GT(TRUE(), TRUE())'], - ['=HF.GT(,)'], - ['=HF.GT(1,)'], - ['=HF.GT("1",)'], - ['=HF.GT(TRUE(),)'], - ['=HF.GT("1", 1)'], - ['=HF.GT(TRUE(), 1)'], - ['=HF.GT(TRUE(), "1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('A2'))).toEqual(false) - expect(engine.getCellValue(adr('A3'))).toEqual(true) - expect(engine.getCellValue(adr('A4'))).toEqual(false) - expect(engine.getCellValue(adr('A5'))).toEqual(true) - expect(engine.getCellValue(adr('A6'))).toEqual(false) - expect(engine.getCellValue(adr('A7'))).toEqual(false) - expect(engine.getCellValue(adr('A8'))).toEqual(true) - expect(engine.getCellValue(adr('A9'))).toEqual(true) - expect(engine.getCellValue(adr('A10'))).toEqual(true) - expect(engine.getCellValue(adr('A11'))).toEqual(true) - expect(engine.getCellValue(adr('A12'))).toEqual(true) - expect(engine.getCellValue(adr('A13'))).toEqual(true) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.GT(NA(),)'], - ['=HF.GT(B2:C2,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfgte.spec.ts b/test/unit/interpreter/function-hfgte.spec.ts deleted file mode 100644 index 85ddf09b42..0000000000 --- a/test/unit/interpreter/function-hfgte.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.GTE', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.GTE(1)', '=HF.GTE(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.GTE(1, 0)'], - ['=HF.GTE(1, 1)'], - ['=HF.GTE("1", "0")'], - ['=HF.GTE("1", "1")'], - ['=HF.GTE(TRUE(), FALSE())'], - ['=HF.GTE(TRUE(), TRUE())'], - ['=HF.GTE(,)'], - ['=HF.GTE(1,)'], - ['=HF.GTE("1",)'], - ['=HF.GTE(TRUE(),)'], - ['=HF.GTE("1", 1)'], - ['=HF.GTE(TRUE(), 1)'], - ['=HF.GTE(TRUE(), "1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('A2'))).toEqual(true) - expect(engine.getCellValue(adr('A3'))).toEqual(true) - expect(engine.getCellValue(adr('A4'))).toEqual(true) - expect(engine.getCellValue(adr('A5'))).toEqual(true) - expect(engine.getCellValue(adr('A6'))).toEqual(true) - expect(engine.getCellValue(adr('A7'))).toEqual(true) - expect(engine.getCellValue(adr('A8'))).toEqual(true) - expect(engine.getCellValue(adr('A9'))).toEqual(true) - expect(engine.getCellValue(adr('A10'))).toEqual(true) - expect(engine.getCellValue(adr('A11'))).toEqual(true) - expect(engine.getCellValue(adr('A12'))).toEqual(true) - expect(engine.getCellValue(adr('A13'))).toEqual(true) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.GTE(NA(),)'], - ['=HF.GTE(B2:C2,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hflt.spec.ts b/test/unit/interpreter/function-hflt.spec.ts deleted file mode 100644 index aa44d5014d..0000000000 --- a/test/unit/interpreter/function-hflt.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.LT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.LT(1)', '=HF.LT(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.LT(1, 0)'], - ['=HF.LT(1, 1)'], - ['=HF.LT("1", "0")'], - ['=HF.LT("1", "1")'], - ['=HF.LT(TRUE(), FALSE())'], - ['=HF.LT(TRUE(), TRUE())'], - ['=HF.LT(,)'], - ['=HF.LT(1,)'], - ['=HF.LT("1",)'], - ['=HF.LT(TRUE(),)'], - ['=HF.LT("1", 1)'], - ['=HF.LT(TRUE(), 1)'], - ['=HF.LT(TRUE(), "1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('A2'))).toEqual(false) - expect(engine.getCellValue(adr('A3'))).toEqual(false) - expect(engine.getCellValue(adr('A4'))).toEqual(false) - expect(engine.getCellValue(adr('A5'))).toEqual(false) - expect(engine.getCellValue(adr('A6'))).toEqual(false) - expect(engine.getCellValue(adr('A7'))).toEqual(false) - expect(engine.getCellValue(adr('A8'))).toEqual(false) - expect(engine.getCellValue(adr('A9'))).toEqual(false) - expect(engine.getCellValue(adr('A10'))).toEqual(false) - expect(engine.getCellValue(adr('A11'))).toEqual(false) - expect(engine.getCellValue(adr('A12'))).toEqual(false) - expect(engine.getCellValue(adr('A13'))).toEqual(false) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.LT(NA(),)'], - ['=HF.LT(B2:C2,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hflte.spec.ts b/test/unit/interpreter/function-hflte.spec.ts deleted file mode 100644 index 2bef54ebcb..0000000000 --- a/test/unit/interpreter/function-hflte.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.LTE', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.LTE(1)', '=HF.LTE(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.LTE(1, 0)'], - ['=HF.LTE(1, 1)'], - ['=HF.LTE("1", "0")'], - ['=HF.LTE("1", "1")'], - ['=HF.LTE(TRUE(), FALSE())'], - ['=HF.LTE(TRUE(), TRUE())'], - ['=HF.LTE(,)'], - ['=HF.LTE(1,)'], - ['=HF.LTE("1",)'], - ['=HF.LTE(TRUE(),)'], - ['=HF.LTE("1", 1)'], - ['=HF.LTE(TRUE(), 1)'], - ['=HF.LTE(TRUE(), "1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('A2'))).toEqual(true) - expect(engine.getCellValue(adr('A3'))).toEqual(false) - expect(engine.getCellValue(adr('A4'))).toEqual(true) - expect(engine.getCellValue(adr('A5'))).toEqual(false) - expect(engine.getCellValue(adr('A6'))).toEqual(true) - expect(engine.getCellValue(adr('A7'))).toEqual(true) - expect(engine.getCellValue(adr('A8'))).toEqual(false) - expect(engine.getCellValue(adr('A9'))).toEqual(false) - expect(engine.getCellValue(adr('A10'))).toEqual(false) - expect(engine.getCellValue(adr('A11'))).toEqual(false) - expect(engine.getCellValue(adr('A12'))).toEqual(false) - expect(engine.getCellValue(adr('A13'))).toEqual(false) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.LTE(NA(),)'], - ['=HF.LTE(B2:C2,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfminus.spec.ts b/test/unit/interpreter/function-hfminus.spec.ts deleted file mode 100644 index f563942a15..0000000000 --- a/test/unit/interpreter/function-hfminus.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.MINUS', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MINUS(1)', '=HF.MINUS(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MINUS(2,3)'], - ['=HF.MINUS(1.0000000000001,1)'], - ['=HF.MINUS(1,)'], - ['=HF.MINUS(,)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MINUS(TRUE(),B1)'], - ['=HF.MINUS("1",)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MINUS("abcd",)'], - ['=HF.MINUS(NA(),)'], - ['=HF.MINUS(B3:C3,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('passes subtypes', () => { - const engine = HyperFormula.buildFromArray([['=HF.MINUS(B1,C1)', '1$', 1]]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - }) -}) diff --git a/test/unit/interpreter/function-hfmultiply.spec.ts b/test/unit/interpreter/function-hfmultiply.spec.ts deleted file mode 100644 index 8e91e583fe..0000000000 --- a/test/unit/interpreter/function-hfmultiply.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.MULTIPLY', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MULTIPLY(1)', '=HF.MULTIPLY(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MULTIPLY(2,3)'], - ['=HF.MULTIPLY(1,)'], - ['=HF.MULTIPLY(,)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MULTIPLY(TRUE(),1)'], - ['=HF.MULTIPLY(B2,1)'], - ['=HF.MULTIPLY("1",1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.MULTIPLY("abcd",)'], - ['=HF.MULTIPLY(NA(),)'], - ['=HF.MULTIPLY(B3:C3,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('passes subtypes', () => { - const engine = HyperFormula.buildFromArray([['=HF.MULTIPLY(B1,C1)', '1$', 1]]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - }) -}) diff --git a/test/unit/interpreter/function-hfne.spec.ts b/test/unit/interpreter/function-hfne.spec.ts deleted file mode 100644 index 46f61cf37b..0000000000 --- a/test/unit/interpreter/function-hfne.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.NE', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.NE(1)', '=HF.NE(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.NE(1, 0)'], - ['=HF.NE(1, 1)'], - ['=HF.NE("1", "0")'], - ['=HF.NE("1", "1")'], - ['=HF.NE(TRUE(), FALSE())'], - ['=HF.NE(TRUE(), TRUE())'], - ['=HF.NE(,)'], - ['=HF.NE(1,)'], - ['=HF.NE("1",)'], - ['=HF.NE(TRUE(),)'], - ['=HF.NE("1", 1)'], - ['=HF.NE(TRUE(), 1)'], - ['=HF.NE(TRUE(), "1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('A2'))).toEqual(false) - expect(engine.getCellValue(adr('A3'))).toEqual(true) - expect(engine.getCellValue(adr('A4'))).toEqual(false) - expect(engine.getCellValue(adr('A5'))).toEqual(true) - expect(engine.getCellValue(adr('A6'))).toEqual(false) - expect(engine.getCellValue(adr('A7'))).toEqual(false) - expect(engine.getCellValue(adr('A8'))).toEqual(true) - expect(engine.getCellValue(adr('A9'))).toEqual(true) - expect(engine.getCellValue(adr('A10'))).toEqual(true) - expect(engine.getCellValue(adr('A11'))).toEqual(true) - expect(engine.getCellValue(adr('A12'))).toEqual(true) - expect(engine.getCellValue(adr('A13'))).toEqual(true) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.NE(NA(),)'], - ['=HF.NE(B2:C2,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfpow.spec.ts b/test/unit/interpreter/function-hfpow.spec.ts deleted file mode 100644 index dadcc127dc..0000000000 --- a/test/unit/interpreter/function-hfpow.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.POW', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.POW(1)', '=HF.POW(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.POW(2, 3)'], - ['=HF.POW(,1)'], - ['=HF.POW(,)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(8) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.POW(TRUE(),B1)'], - ['=HF.POW("1",)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.POW("abcd",)'], - ['=HF.POW(NA(),)'], - ['=HF.POW(B3:C3,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfuminus.spec.ts b/test/unit/interpreter/function-hfuminus.spec.ts deleted file mode 100644 index 8ee67e12f1..0000000000 --- a/test/unit/interpreter/function-hfuminus.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.UMINUS', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UMINUS()', '=HF.UMINUS(1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UMINUS(2)'], - ['=HF.UMINUS(-3)'], - ['=HF.UMINUS(0)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-2) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UMINUS(TRUE())'], - ['=HF.UMINUS(B2)'], - ['=HF.UMINUS("1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(-1) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UMINUS("abcd")'], - ['=HF.UMINUS(NA())'], - ['=HF.UMINUS(B3:C3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfunary_percent.spec.ts b/test/unit/interpreter/function-hfunary_percent.spec.ts deleted file mode 100644 index 95a2860c10..0000000000 --- a/test/unit/interpreter/function-hfunary_percent.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.UNARY_PERCENT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UNARY_PERCENT()', '=HF.UNARY_PERCENT(1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UNARY_PERCENT(2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.02) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UNARY_PERCENT(TRUE())'], - ['=HF.UNARY_PERCENT(B2)'], - ['=HF.UNARY_PERCENT("1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.01) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(0.01) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UNARY_PERCENT("abcd")'], - ['=HF.UNARY_PERCENT(NA())'], - ['=HF.UNARY_PERCENT(B3:C3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hfuplus.spec.ts b/test/unit/interpreter/function-hfuplus.spec.ts deleted file mode 100644 index 687998f31d..0000000000 --- a/test/unit/interpreter/function-hfuplus.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HF.UPLUS', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UPLUS()', '=HF.UPLUS(1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UPLUS(2)'], - ['=HF.UPLUS(-3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(-3) - }) - - it('should coerce to correct types', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UPLUS(TRUE())'], - ['=HF.UPLUS(B2)'], - ['=HF.UPLUS("1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('should throw correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=HF.UPLUS("abcd")'], - ['=HF.UPLUS(NA())'], - ['=HF.UPLUS(B3:C3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-hlookup.spec.ts b/test/unit/interpreter/function-hlookup.spec.ts deleted file mode 100644 index 99e1ab2d08..0000000000 --- a/test/unit/interpreter/function-hlookup.spec.ts +++ /dev/null @@ -1,358 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HLOOKUP', () => { - describe('HLOOKUP - args validation', () => { - it('not enough parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1, A2:B3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('too many parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1, A2:B3, 2, TRUE(), "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('wrong type of first argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(D1:E1, A2:B3, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('wrong type of second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1, "foo", 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('wrong type of third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1, A2:B3, "foo", TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong type of fourth argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1, A2:B3, 2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should return error when index argument greater that range height', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1, A2:B3, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.IndexLarge)) - }) - - it('should return error when index is less than one', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1, C3:D5, 0)'], - ['=HLOOKUP(1, C2:D3, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('should return #VALUE error when the found value is a range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4', '5'], - ['a', '=D2:E2', 'c', 'd', 'e'], - ['=HLOOKUP(2, A1:E2, 2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should propagate errors properly', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(1/0, B1:B1, 1)'], - ['=HLOOKUP(1, B1:B1, 1/0)'], - ['=HLOOKUP(1, A10:A11, 1, NA())'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA)) - }) - }) - - describe('HLOOKUP', () => { - it('should find value in sorted range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4', '5'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(2, A1:E2, 2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('b') - }) - - it('should find value in sorted range using linearSearch', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4', '5'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(2, A1:E2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('b') - }) - - it('should return the first matching value if RangeLookup = FALSE', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '2', '2', '5'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(2, A1:E2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('b') - }) - - it('should return the last matching value if RangeLookup = TRUE', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '2', '2', '5'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(2, A1:E2, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('d') - }) - - it('works with wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 1, 'aaaa', 'ddaa', 'abcd'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP("*c*", A1:E2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('e') - }) - - it('returns error when there is no matching value for the wildcard pattern', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 1, 'aaaa', 'ddaa', 'abbd'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP("*c*", A1:E2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('on sorted data ignores wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 1, '*c*', 'ddaa', 'abcd'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP("*c*", A1:E2, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('c') - }) - - it('should find value in unsorted range using linearSearch', () => { - const engine = HyperFormula.buildFromArray([ - ['5', '4', '3', '2', '1'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(2, A1:E2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('d') - }) - - it('should find value in sorted range with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '=TRUE()', 'foo'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(TRUE(), A1:E2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('d') - }) - - it('should find value in unsorted range with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', '4', 'foo', '2', 'bar'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(2, A1:E2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('d') - }) - - it('should return the lower bound for sorted values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '8'], - ['a', 'b', 'c'], - ['=HLOOKUP(4, A1:C2, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('b') - }) - - it('should return the lower bound for sorted values if all are smaller than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['a', 'b', 'c'], - ['=HLOOKUP(4, A1:C2, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('c') - }) - - it('should return error when all values are greater', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['a', 'b', 'c'], - ['=HLOOKUP(0, A1:C2, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should return error when value not present using linear search', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['a', 'b', 'c'], - ['=HLOOKUP(4, A1:C2, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should find value if index build during evaluation', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1', '2'], - ['a', 'b', 'c'], - ['=HLOOKUP(1, A1:C2, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('b') - }) - - it('should properly calculate absolute row index', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(3, C1:E1, 1, TRUE())', 'foo', '1', '2', '3'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should calculate indexes properly when using binary search', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(4, E1:J1, 1, TRUE())', null, null, null, '1', '2', '3', '4', '5'] - ], {useColumnIndex: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('should calculate indexes properly when using naive approach', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(4, E1:J1, 1, TRUE())', null, null, null, '1', '2', '3', '4', '5'] - ], {useColumnIndex: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('should coerce empty arg to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '2', '3', '4', '5'], - ['a', 'b', 'c', 'd', 'e'], - ['=HLOOKUP(F3, A1:E2, 2)'], - ['=HLOOKUP(, A1:E2, 2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual('a') - expect(engine.getCellValue(adr('A4'))).toEqual('a') - }) - - it('should not coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP("1", A2:C2, 1)'], - [1, 2, 3], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should properly report no match', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP("0", A2:D2, 1)'], - [1, 2, 3, '\'1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should properly report approximate matching', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP("2", A2:D2, 1)'], - [1, 2, 3, '\'1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - }) - - it('should coerce null to zero when using naive approach', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(, A2:C2, 1, FALSE())'], - [1, 3, 0], - ], {useColumnIndex: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - }) - - it('should work on row ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=HLOOKUP(2,2:3,2)'], - [1, 2, 3], - ['a', 'b', 'c'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual('b') - }) - - it('works for strings, is not case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'b', 'c', 'A', 'B'], - [1, 2, 3, 4, 5], - ['=HLOOKUP("A", A1:E2, 2, FALSE())'] - ], {caseSensitive: false}) - - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('works for strings, is not case sensitive even if config defines case sensitivity', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'b', 'c', 'A', 'B'], - [1, 2, 3, 4, 5], - ['=HLOOKUP("A", A1:E2, 2, FALSE())'] - ], {caseSensitive: true}) - - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('should find value in sorted range', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'B', 'c', 'd', 'e'], - [1, 2, 3, 4, 5], - ['=HLOOKUP("b", A1:E2, 2)'], - ], {caseSensitive: false}) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/function-hour.spec.ts b/test/unit/interpreter/function-hour.spec.ts deleted file mode 100644 index 6211993377..0000000000 --- a/test/unit/interpreter/function-hour.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HOUR', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=HOUR("foo")', '=HOUR("12/30/2018")', '=HOUR(1, 2)', '=HOUR()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([['=HOUR(0.5123456)', '=HOUR(0)', '=HOUR(0.999999)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=HOUR("14:42:59")', '=HOUR("01/01/1900 03:01:02am")', '=HOUR("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(14) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - - it('use datenumber coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=HOUR(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=HOUR(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-hyperlink.spec.ts b/test/unit/interpreter/function-hyperlink.spec.ts deleted file mode 100644 index c292899855..0000000000 --- a/test/unit/interpreter/function-hyperlink.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HYPERLINK', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HYPERLINK()', '=HYPERLINK("s1","s2","s3")'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with only url argument', () => { - const url = 'https://hyperformula.handsontable.com/' - const engine = HyperFormula.buildFromArray([[`=HYPERLINK("${url}")`]]) - expect(engine.getCellValue(adr('A1'))).toEqual(url) - }) - - it('with url and label arguments', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const engine = HyperFormula.buildFromArray([[`=HYPERLINK("${url}","${linkLabel}")`]]) - expect(engine.getCellValue(adr('A1'))).toEqual(linkLabel) - }) - - it('when not the root expression', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const prefix = 'Prefix: ' - const engine = HyperFormula.buildFromArray([[`=CONCATENATE("${prefix}",HYPERLINK("${url}","${linkLabel}"))`]]) - expect(engine.getCellValue(adr('A1'))).toEqual(prefix + linkLabel) - }) - - it('when arguments are simple references', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const engine = HyperFormula.buildFromArray([[url, linkLabel, '=HYPERLINK(A1,B1)']]) - expect(engine.getCellValue(adr('C1'))).toEqual(linkLabel) - }) - - it('when arguments are complex', () => { - const url = 'https://hyperformula.handsontable.com/' - const linkLabel = 'HyperFormula' - const engine = HyperFormula.buildFromArray([[url, linkLabel, '=HYPERLINK(INDEX(A:A,ROW()),B1)']]) - expect(engine.getCellValue(adr('C1'))).toEqual(linkLabel) - }) -}) diff --git a/test/unit/interpreter/function-hypgeom.dist.spec.ts b/test/unit/interpreter/function-hypgeom.dist.spec.ts deleted file mode 100644 index 7ecefb6a66..0000000000 --- a/test/unit/interpreter/function-hypgeom.dist.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function HYPGEOM.DIST', () => { - //In product #1, function takes 4 arguments. - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=HYPGEOM.DIST(1, 2, 3, 4)'], - ['=HYPGEOM.DIST(1, 2, 3, 4, 5, 6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - //In product #1, function takes 4 arguments. - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=HYPGEOM.DIST("foo", 2, 3, 4, TRUE())'], - ['=HYPGEOM.DIST(1, "baz", 3, 4, TRUE())'], - ['=HYPGEOM.DIST(1, 2, "baz", 4, TRUE())'], - ['=HYPGEOM.DIST(1, 2, 3, "baz", TRUE())'], - ['=HYPGEOM.DIST(1, 1, 1, 1, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - //In product #1, function takes 4 arguments. - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=HYPGEOM.DIST(4, 12, 20, 40, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.150422391245528, 6) - }) - - //In product #1, function takes 4 arguments. - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=HYPGEOM.DIST(4, 12, 20, 40, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.109243002735772, 6) - }) - - //In product #1, function takes 4 arguments. - it('truncation works', () => { - const engine = HyperFormula.buildFromArray([ - ['=HYPGEOM.DIST(4.9, 12, 20, 40, TRUE())'], - ['=HYPGEOM.DIST(4, 12.9, 20, 40, TRUE())'], - ['=HYPGEOM.DIST(4, 12, 20.9, 40, TRUE())'], - ['=HYPGEOM.DIST(4, 12, 20, 40.9, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.150422391245528, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.150422391245528, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.150422391245528, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(0.150422391245528, 6) - }) - - //In product #1, function takes 4 arguments. - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=HYPGEOM.DIST(0, 12, 20, 40, TRUE())'], - ['=HYPGEOM.DIST(-1, 12, 20, 40, TRUE())'], - ['=HYPGEOM.DIST(12, 12, 20, 40, TRUE())'], - ['=HYPGEOM.DIST(12.1, 12, 20, 40, TRUE())'], - ['=HYPGEOM.DIST(12, 20, 12, 40, TRUE())'], - ['=HYPGEOM.DIST(12.1, 20, 12, 40, TRUE())'], - ['=HYPGEOM.DIST(4, 20, 4, 20, TRUE())'], - ['=HYPGEOM.DIST(4, 20, 4, 19.9, TRUE())'], - ['=HYPGEOM.DIST(4, 4, 20, 20, TRUE())'], - ['=HYPGEOM.DIST(4, 4, 20, 19.9, TRUE())'], - ['=HYPGEOM.DIST(10, 20, 20, 30, TRUE())'], - ['=HYPGEOM.DIST(10, 20.1, 20, 30, TRUE())'], - ['=HYPGEOM.DIST(0, 0.1, 0.1, 0.9, TRUE())'], - ['=HYPGEOM.DIST(10.9, 21, 20, 30.9, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0000225475753840604, 6) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - //product #2 returns value here - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - //product #2 returns value here - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A9'))).toEqual(1) - expect(engine.getCellValue(adr('A10'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A11'))).toBeCloseTo(0.00614930629923134, 6) - //product #2 returns value here - expect(engine.getCellValue(adr('A12'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A13'))).toEqual(1) - //value should be 0 or Error, product #1 gives different answer - expect(engine.getCellValue(adr('A14'))).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/function-if.spec.ts b/test/unit/interpreter/function-if.spec.ts deleted file mode 100644 index 1014de7cf6..0000000000 --- a/test/unit/interpreter/function-if.spec.ts +++ /dev/null @@ -1,139 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IF', () => { - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=IF(TRUE(), "no", 1, 2)', '=IF(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('when value is true', () => { - const engine = HyperFormula.buildFromArray([['=IF(TRUE(), "yes", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('when value is false', () => { - const engine = HyperFormula.buildFromArray([['=IF(FALSE(), "yes", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('no') - }) - - it('coercing empty string', () => { - const engine = HyperFormula.buildFromArray([['', '=IF(A1, "yes", "no")']]) - expect(engine.getCellValue(adr('B1'))).toEqual('no') - }) - - it('when condition is weird type', () => { - const engine = HyperFormula.buildFromArray([['=IF("foo", "yes", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([['=IF("TRUE", "yes", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('returns error if condition is an error', () => { - const engine = HyperFormula.buildFromArray([['=IF(4/0, "yes", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('passes errors', () => { - const engine = HyperFormula.buildFromArray([['=IF(TRUE(), 4/0, "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('passes subtypes of second arg', () => { - const engine = HyperFormula.buildFromArray([['=IF(TRUE(),B1,C1)', '1%', '1']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('passes subtypes of third arg', () => { - const engine = HyperFormula.buildFromArray([['=IF(FALSE(),B1,C1)', '1', '1%']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('passes correct value when other arg is an error', () => { - const engine = HyperFormula.buildFromArray([['=IF(FALSE(), 4/0, "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('no') - }) - - it('when condition is number', () => { - const engine = HyperFormula.buildFromArray([['=IF(1, "yes", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('when condition is logic function', () => { - const engine = HyperFormula.buildFromArray([['=IF(OR(1, FALSE()), "yes", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('works when only first part is given', () => { - const engine = HyperFormula.buildFromArray([['=IF(TRUE(), "yes")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('works when only first part is given and condition is false', () => { - const engine = HyperFormula.buildFromArray([['=IF(FALSE(), "yes")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - ['1'], - ['3'], - ['=IF(A1:A3,"yes","no")'], - ['=IF(A1:A3,"yes","no")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('works when condition contains a reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', '=IF(A1, "yes", "no")'], - ['=FALSE()', '=IF(A2, "yes", "no")'] - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('yes') - expect(engine.getCellValue(adr('B2'))).toEqual('no') - }) - - it('works when condition is an expression', () => { - const engine = HyperFormula.buildFromArray([['=IF(1<100, "yes", "no")', '=IF(1000<100, "yes", "no")']]) - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - expect(engine.getCellValue(adr('B1'))).toEqual('no') - }) - - it('works when condition is an expression with cell references', () => { - const engine = HyperFormula.buildFromArray([['10', '=IF(A1<100, "yes", "no")', '=IF(A1<1, "yes", "no")']]) - expect(engine.getCellValue(adr('B1'))).toEqual('yes') - expect(engine.getCellValue(adr('C1'))).toEqual('no') - }) - - it('works when condition references a cell with formula inside', () => { - const engine = HyperFormula.buildFromArray([ - ['100'], - ['300'], - ['=AVERAGE(A1,A2)'], - ['=IF(A3<100,"True","False")'] - ]) - expect(engine.getCellValue(adr('A3'))).toEqual(200) - expect(engine.getCellValue(adr('A4'))).toEqual('False') - }) -}) diff --git a/test/unit/interpreter/function-iferror.spec.ts b/test/unit/interpreter/function-iferror.spec.ts deleted file mode 100644 index 62ea97b4c8..0000000000 --- a/test/unit/interpreter/function-iferror.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IFERROR', () => { - it('Should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IFERROR(1)', '=IFERROR(2,3,4)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - it('when no error', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR("abcd", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('abcd') - }) - - it('preserves types of first arg', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR(B1, 1)', '1%']]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('preserves types of second arg', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR(NA(), B1)', '1%']]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('when left-error', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR(1/0, "yes")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('when right-error', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR("yes", 1/0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('when both-error', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR(#VALUE!, 1/0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when range', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR("yes", A2:A3)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('when cycle', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR(B1, 1)', '=B1']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('when left-parsing error', () => { - const engine = HyperFormula.buildFromArray([['=IFERROR(B1, 1/0)', '=SUM(']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-ifna.spec.ts b/test/unit/interpreter/function-ifna.spec.ts deleted file mode 100644 index 0f48a8c3ef..0000000000 --- a/test/unit/interpreter/function-ifna.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IFNA', () => { - it('Should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IFNA(1)', '=IFNA(2, 3, 4)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - it('when no error', () => { - const engine = HyperFormula.buildFromArray([['=IFNA("abcd", "no")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('abcd') - }) - - it('when left-error NA', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(COS(1, 1), "yes")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('when left-error DIV0', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(1/0, "yes")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when right-error', () => { - const engine = HyperFormula.buildFromArray([['=IFNA("yes", 1/0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('yes') - }) - - it('when both-error', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(COS(1, 1), 1/0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when both-error 2', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(1/0, COS(1, 1))']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when range', () => { - const engine = HyperFormula.buildFromArray([['=IFNA("yes", A2:A3)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('when cycle', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(B1, 1)', '=B1']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) - - it('when cycle 2', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(1, B1)', '=B1']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('preserves types of first arg', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(B1, 1)', '1%']]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('preserves types of second arg', () => { - const engine = HyperFormula.buildFromArray([['=IFNA(NA(), B1)', '1%']]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) -}) diff --git a/test/unit/interpreter/function-ifs.spec.ts b/test/unit/interpreter/function-ifs.spec.ts deleted file mode 100644 index e153e21457..0000000000 --- a/test/unit/interpreter/function-ifs.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IFS', () => { - it('Should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - [10, '=IFS()'], - [20, '=IFS(A1>90)'], - [30, '=IFS(A1>90, "A", A1>80)'], - ]) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('Should not work for wrong number of arguments when array arithmetic is on', () => { - const engine = HyperFormula.buildFromArray([ - [10, '=IFS()'], - [20, '=IFS(A1>90)'], - [30, '=IFS(A1>90, "A", A1>80)'], - ], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('Nominal operation', () => { - const engine = HyperFormula.buildFromArray([ - [11, '=IFS(A1>30, "A", A1>20, "B", A1>10, "C")'], - [21, '=IFS(A2>30, "A", A2>20, "B", A2>10, "C")'], - [31, '=IFS(A3>30, "A", A3>20, "B", A3>10, "C")'], - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('C') - expect(engine.getCellValue(adr('B2'))).toEqual('B') - expect(engine.getCellValue(adr('B3'))).toEqual('A') - }) - - it('Return first match', () => { - const engine = HyperFormula.buildFromArray([ - [11, '=IFS(A1>10, "A", A1>10, "B", A1>10, "C")'], - [21, '=IFS(A2>10, "A", A2>10, "B", A2>10, "C")'], - [31, '=IFS(A3>10, "A", A3>10, "B", A3>10, "C")'], - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('A') - expect(engine.getCellValue(adr('B2'))).toEqual('A') - expect(engine.getCellValue(adr('B3'))).toEqual('A') - }) - - it('No match found', () => { - const engine = HyperFormula.buildFromArray([ - [10, '=IFS(A1>90, "A", A1>80, "B", A1>70, "C")'] - ]) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.NoConditionMet)) - }) -}) diff --git a/test/unit/interpreter/function-imabs.spec.ts b/test/unit/interpreter/function-imabs.spec.ts deleted file mode 100644 index a15d224d64..0000000000 --- a/test/unit/interpreter/function-imabs.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMABS', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMABS()'], - ['=IMABS(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMABS("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMABS(0)'], - ['=IMABS("i")'], - ['=IMABS("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - }) -}) diff --git a/test/unit/interpreter/function-imaginary.spec.ts b/test/unit/interpreter/function-imaginary.spec.ts deleted file mode 100644 index fc3040b332..0000000000 --- a/test/unit/interpreter/function-imaginary.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMAGINARY', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMAGINARY()'], - ['=IMAGINARY(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMAGINARY("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMAGINARY(0)'], - ['=IMAGINARY("i")'], - ['=IMAGINARY("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - }) -}) diff --git a/test/unit/interpreter/function-imargument.spec.ts b/test/unit/interpreter/function-imargument.spec.ts deleted file mode 100644 index e223b6155c..0000000000 --- a/test/unit/interpreter/function-imargument.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMARGUMENT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMARGUMENT()'], - ['=IMARGUMENT(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMARGUMENT("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMARGUMENT(0)'], - ['=IMARGUMENT("i")'], - ['=IMARGUMENT("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.5707963267949, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(2.21429743558818) - }) -}) diff --git a/test/unit/interpreter/function-imconjugate.spec.ts b/test/unit/interpreter/function-imconjugate.spec.ts deleted file mode 100644 index 99d516d5bd..0000000000 --- a/test/unit/interpreter/function-imconjugate.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMCONJUGATE', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCONJUGATE()'], - ['=IMCONJUGATE(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCONJUGATE("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCONJUGATE(0)'], - ['=IMCONJUGATE("i")'], - ['=IMCONJUGATE("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0') - expect(engine.getCellValue(adr('A2'))).toEqual('-i') - expect(engine.getCellValue(adr('A3'))).toEqual('-3-4i') - }) -}) diff --git a/test/unit/interpreter/function-imcos.spec.ts b/test/unit/interpreter/function-imcos.spec.ts deleted file mode 100644 index 2599353fc3..0000000000 --- a/test/unit/interpreter/function-imcos.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMCOS', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOS()'], - ['=IMCOS(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOS("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOS(0)'], - ['=IMCOS("i")'], - ['=IMCOS("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '1') - expectToBeCloseForComplex(engine, 'A2', '1.5430806348') - expectToBeCloseForComplex(engine, 'A3', '-27.0349456030742+3.85115333481178i') - }) -}) diff --git a/test/unit/interpreter/function-imcosh.spec.ts b/test/unit/interpreter/function-imcosh.spec.ts deleted file mode 100644 index d141acfcc3..0000000000 --- a/test/unit/interpreter/function-imcosh.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMCOSH', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOSH()'], - ['=IMCOSH(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOSH("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOSH(0)'], - ['=IMCOSH("i")'], - ['=IMCOSH("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '1') - expectToBeCloseForComplex(engine, 'A2', '0.5403023058681398') - expectToBeCloseForComplex(engine, 'A3', '-6.58066304055116+7.58155274274655i') - }) -}) diff --git a/test/unit/interpreter/function-imcot.spec.ts b/test/unit/interpreter/function-imcot.spec.ts deleted file mode 100644 index 00d5e67114..0000000000 --- a/test/unit/interpreter/function-imcot.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMCOT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOT()'], - ['=IMCOT(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOT("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCOT(0)'], - ['=IMCOT("i")'], - ['=IMCOT("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expectToBeCloseForComplex(engine, 'A2', '-1.31303528549933i') - expectToBeCloseForComplex(engine, 'A3', '0.000187587737983659-1.00064439247156i') - }) -}) diff --git a/test/unit/interpreter/function-imcsc.spec.ts b/test/unit/interpreter/function-imcsc.spec.ts deleted file mode 100644 index c0bafd545e..0000000000 --- a/test/unit/interpreter/function-imcsc.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMCSC', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCSC()'], - ['=IMCSC(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCSC("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCSC(0)'], - ['=IMCSC("i")'], - ['=IMCSC("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expectToBeCloseForComplex(engine, 'A2', '-0.850918128239322i') - expectToBeCloseForComplex(engine, 'A3', '-0.0051744731840194+0.036275889628626i') - }) -}) diff --git a/test/unit/interpreter/function-imcsch.spec.ts b/test/unit/interpreter/function-imcsch.spec.ts deleted file mode 100644 index 704ab8d961..0000000000 --- a/test/unit/interpreter/function-imcsch.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMCSCH', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCSCH()'], - ['=IMCSCH(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCSCH("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMCSCH(0)'], - ['=IMCSCH("i")'], - ['=IMCSCH("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expectToBeCloseForComplex(engine, 'A2', '-1.18839510577812i') - expectToBeCloseForComplex(engine, 'A3', '0.0648774713706355+0.0754898329158637i') - }) -}) diff --git a/test/unit/interpreter/function-imdiv.spec.ts b/test/unit/interpreter/function-imdiv.spec.ts deleted file mode 100644 index 9c678df332..0000000000 --- a/test/unit/interpreter/function-imdiv.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMDIV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMDIV(1)'], - ['=IMDIV(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMDIV("foo", 1)'], - ['=IMDIV(1, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMDIV(0, 1)'], - ['=IMDIV("i", "-i")'], - ['=IMDIV("-3+4i", "1+i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0') - expect(engine.getCellValue(adr('A2'))).toEqual('-1') - expect(engine.getCellValue(adr('A3'))).toEqual('0.5+3.5i') - }) -}) diff --git a/test/unit/interpreter/function-imexp.spec.ts b/test/unit/interpreter/function-imexp.spec.ts deleted file mode 100644 index d1a1b9dc60..0000000000 --- a/test/unit/interpreter/function-imexp.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMEXP', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMEXP()'], - ['=IMEXP(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMEXP("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMEXP(0)'], - ['=IMEXP("i")'], - ['=IMEXP("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '1') - expectToBeCloseForComplex(engine, 'A2', '0.54030230586814+0.841470984807897i') - expectToBeCloseForComplex(engine, 'A3', '-0.0325429996401548-0.0376789775748659i') - }) -}) diff --git a/test/unit/interpreter/function-imln.spec.ts b/test/unit/interpreter/function-imln.spec.ts deleted file mode 100644 index 0b3ed4f19b..0000000000 --- a/test/unit/interpreter/function-imln.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMLN', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLN()'], - ['=IMLN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLN("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLN(0)'], - ['=IMLN("i")'], - ['=IMLN("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expectToBeCloseForComplex(engine, 'A2', '1.5707963267949i') - expectToBeCloseForComplex(engine, 'A3', '1.6094379124341+2.21429743558818i') - }) -}) diff --git a/test/unit/interpreter/function-imlog10.spec.ts b/test/unit/interpreter/function-imlog10.spec.ts deleted file mode 100644 index c708e2088a..0000000000 --- a/test/unit/interpreter/function-imlog10.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMLOG10', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLOG10()'], - ['=IMLOG10(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLOG10("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLOG10(0)'], - ['=IMLOG10("i")'], - ['=IMLOG10("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expectToBeCloseForComplex(engine, 'A2', '0.682188176920921i') - expectToBeCloseForComplex(engine, 'A3', '0.698970004336019+0.961657157568468i') - }) -}) diff --git a/test/unit/interpreter/function-imlog2.spec.ts b/test/unit/interpreter/function-imlog2.spec.ts deleted file mode 100644 index d07892410d..0000000000 --- a/test/unit/interpreter/function-imlog2.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMLOG2', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLOG2()'], - ['=IMLOG2(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLOG2("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMLOG2(0)'], - ['=IMLOG2("i")'], - ['=IMLOG2("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expectToBeCloseForComplex(engine, 'A2', '2.2661800709136i') - expectToBeCloseForComplex(engine, 'A3', '2.32192809488736+3.19455592937622i') - }) -}) diff --git a/test/unit/interpreter/function-impower.spec.ts b/test/unit/interpreter/function-impower.spec.ts deleted file mode 100644 index 533e3ee32b..0000000000 --- a/test/unit/interpreter/function-impower.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMPOWER', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMPOWER(1)'], - ['=IMPOWER(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMPOWER("foo", 2)'], - ['=IMPOWER(1, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMPOWER(0, 1)'], - ['=IMPOWER("-4", 0.1)'], - ['=IMPOWER("-3+4i", -1)'], - ['=IMPOWER(0, -1)'], - ['=IMPOWER(0, 0)'], - ['=IMPOWER("i", 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0') - expectToBeCloseForComplex(engine, 'A2', '1.09247705577745+0.35496731310463i') - expectToBeCloseForComplex(engine, 'A3', '-0.12-0.16i') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A6'))).toEqual('1') - }) -}) diff --git a/test/unit/interpreter/function-improduct.spec.ts b/test/unit/interpreter/function-improduct.spec.ts deleted file mode 100644 index 7194ccff50..0000000000 --- a/test/unit/interpreter/function-improduct.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMPRODUCT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMPRODUCT()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should coerce explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMPRODUCT(0)'], - ['=IMPRODUCT("i", "-1.5")'], - ['=IMPRODUCT("-3+4i", "1+i", 1, 2, "3")'], - ['=IMPRODUCT("i",)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0') - expect(engine.getCellValue(adr('A2'))).toEqual('-1.5i') - expect(engine.getCellValue(adr('A3'))).toEqual('-42+6i') - expect(engine.getCellValue(adr('A4'))).toEqual('i') - }) - - it('should fail for non-coercible explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMPRODUCT(1, TRUE())'], - ['=IMPRODUCT(2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should not coerce range arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMPRODUCT(B1:C1)', 1, '2+i'], - ['=IMPRODUCT(B2:D2)', 1, null, null], - ['=IMPRODUCT(B3:D3)', 'i', 'abcd', true], - ['=IMPRODUCT(B4:D4,)', 'i', '=NA()', 1], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('2+i') - expect(engine.getCellValue(adr('A2'))).toEqual('1') - expect(engine.getCellValue(adr('A3'))).toEqual('i') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-imreal.spec.ts b/test/unit/interpreter/function-imreal.spec.ts deleted file mode 100644 index 35a7cbe856..0000000000 --- a/test/unit/interpreter/function-imreal.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMREAL', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMREAL()'], - ['=IMREAL(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMREAL("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMREAL(1)'], - ['=IMREAL("i")'], - ['=IMREAL("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(-3) - }) -}) diff --git a/test/unit/interpreter/function-imsec.spec.ts b/test/unit/interpreter/function-imsec.spec.ts deleted file mode 100644 index 38c7f112b4..0000000000 --- a/test/unit/interpreter/function-imsec.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMSEC', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSEC()'], - ['=IMSEC(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSEC("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSEC(0)'], - ['=IMSEC("i")'], - ['=IMSEC("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '1') - expectToBeCloseForComplex(engine, 'A2', '0.648054273663885') - expectToBeCloseForComplex(engine, 'A3', '-0.0362534969158689-0.00516434460775318i') - }) -}) diff --git a/test/unit/interpreter/function-imsech.spec.ts b/test/unit/interpreter/function-imsech.spec.ts deleted file mode 100644 index a4ea4e1313..0000000000 --- a/test/unit/interpreter/function-imsech.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMSECH', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSECH()'], - ['=IMSECH(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSECH("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSECH(0)'], - ['=IMSECH("i")'], - ['=IMSECH("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '1') - expectToBeCloseForComplex(engine, 'A2', '1.85081571768093') - expectToBeCloseForComplex(engine, 'A3', '-0.0652940278579471-0.0752249603027732i') - }) -}) diff --git a/test/unit/interpreter/function-imsin.spec.ts b/test/unit/interpreter/function-imsin.spec.ts deleted file mode 100644 index bccd6e7f20..0000000000 --- a/test/unit/interpreter/function-imsin.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMSIN', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSIN()'], - ['=IMSIN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSIN("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSIN(0)'], - ['=IMSIN("i")'], - ['=IMSIN("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '0') - expectToBeCloseForComplex(engine, 'A2', '1.1752011936438i') - expectToBeCloseForComplex(engine, 'A3', '-3.85373803791938-27.0168132580039i') - }) -}) diff --git a/test/unit/interpreter/function-imsinh.spec.ts b/test/unit/interpreter/function-imsinh.spec.ts deleted file mode 100644 index 5f71810254..0000000000 --- a/test/unit/interpreter/function-imsinh.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMSINH', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSINH()'], - ['=IMSINH(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSINH("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSINH(0)'], - ['=IMSINH("i")'], - ['=IMSINH("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '0') - expectToBeCloseForComplex(engine, 'A2', '0.841470984807897i') - expectToBeCloseForComplex(engine, 'A3', '6.548120040911-7.61923172032141i') - }) -}) diff --git a/test/unit/interpreter/function-imsqrt.spec.ts b/test/unit/interpreter/function-imsqrt.spec.ts deleted file mode 100644 index 5973b6ff8a..0000000000 --- a/test/unit/interpreter/function-imsqrt.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMSQRT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSQRT()'], - ['=IMSQRT(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSQRT("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSQRT(0)'], - ['=IMSQRT("-4")'], - ['=IMSQRT("-3+4i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0') - expectToBeCloseForComplex(engine, 'A2', '2i') - expectToBeCloseForComplex(engine, 'A3', '1+2i') - }) -}) diff --git a/test/unit/interpreter/function-imsub.spec.ts b/test/unit/interpreter/function-imsub.spec.ts deleted file mode 100644 index 9ce4a11785..0000000000 --- a/test/unit/interpreter/function-imsub.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMSUB', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSUB(1)'], - ['=IMSUB(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSUB("foo", 1)'], - ['=IMSUB(1, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSUB(0, 1)'], - ['=IMSUB("i", "-i")'], - ['=IMSUB("-3+4i", "1+i")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('-1') - expect(engine.getCellValue(adr('A2'))).toEqual('2i') - expect(engine.getCellValue(adr('A3'))).toEqual('-4+3i') - }) -}) diff --git a/test/unit/interpreter/function-imsum.spec.ts b/test/unit/interpreter/function-imsum.spec.ts deleted file mode 100644 index 49b95e48d4..0000000000 --- a/test/unit/interpreter/function-imsum.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IMSUM', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSUM()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should coerce explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSUM(0)'], - ['=IMSUM("i", "-1.5")'], - ['=IMSUM("-3+4i", "1+i", 1, 2, "3")'], - ['=IMSUM("i",)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0') - expect(engine.getCellValue(adr('A2'))).toEqual('-1.5+i') - expect(engine.getCellValue(adr('A3'))).toEqual('4+5i') - expect(engine.getCellValue(adr('A4'))).toEqual('i') - }) - - it('should fail for non-coercible explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSUM(1, TRUE())'], - ['=IMSUM(2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should not coerce range arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMSUM(B1:C1)', 1, '2+i'], - ['=IMSUM(B2:D2)', 1, null, null], - ['=IMSUM(B3:D3)', 'i', 'abcd', true], - ['=IMSUM(B4:D4,)', 'i', '=NA()', 1], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('3+i') - expect(engine.getCellValue(adr('A2'))).toEqual('1') - expect(engine.getCellValue(adr('A3'))).toEqual('i') - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-imtan.spec.ts b/test/unit/interpreter/function-imtan.spec.ts deleted file mode 100644 index b184650709..0000000000 --- a/test/unit/interpreter/function-imtan.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectToBeCloseForComplex} from '../testUtils' - -describe('Function IMTAN', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMTAN()'], - ['=IMTAN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMTAN("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ComplexNumberExpected)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=IMTAN(0)'], - ['=IMTAN("i")'], - ['=IMTAN("-3+4i")'], - ]) - - expectToBeCloseForComplex(engine, 'A1', '0') - expectToBeCloseForComplex(engine, 'A2', '0.761594155955765i') - expectToBeCloseForComplex(engine, 'A3', '0.000187346204629478+0.999355987381473i') - }) -}) diff --git a/test/unit/interpreter/function-index.spec.ts b/test/unit/interpreter/function-index.spec.ts deleted file mode 100644 index a8e15f9202..0000000000 --- a/test/unit/interpreter/function-index.spec.ts +++ /dev/null @@ -1,118 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function INDEX', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=INDEX()'], - ['=INDEX(B1:D3, 1, 1, 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('requires 2nd and 3rd arguments to be integers', () => { - const engine = HyperFormula.buildFromArray([ - ['=INDEX(B1:B1, "foo", 1)'], - ['=INDEX(B1:B1, 1, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('requires 2nd argument to be in bounds of range', () => { - const engine = HyperFormula.buildFromArray([ - ['=INDEX(B1:D3, -1, 1)'], - ['=INDEX(B1:D3, 4, 1)'], - ['=INDEX(42, -1, 1)'], - ['=INDEX(42, 2, 1)'], - ['=INDEX(B1, -1, 1)'], - ['=INDEX(B1, 2, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('requires 2nd and 3rd arguments to be in bounds of range', () => { - const engine = HyperFormula.buildFromArray([ - ['=INDEX(B1:D3, 1, -1)'], - ['=INDEX(B1:D3, 1, 4)'], - ['=INDEX(42, 1, -1)'], - ['=INDEX(42, 1, 2)'], - ['=INDEX(B1, 1, -1)'], - ['=INDEX(B1, 1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('works for range and nonzero arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=INDEX(B1:C2, 1, 1)', '1', '2'], - ['=INDEX(B1:C2, 1, 2)', '3', '4'], - ['=INDEX(B1:C2, 2, 1)'], - ['=INDEX(B1:C2, 2, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('should propagate errors properly', () => { - const engine = HyperFormula.buildFromArray([ - ['=INDEX(B1:C3, 1, 1/0)'], - ['=INDEX(NA(), 1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should return VALUE error when one of the cooridnate is 0 or null', () => { - const engine = HyperFormula.buildFromArray([ - ['=INDEX(B1:D5, 0, 2)'], - ['=INDEX(B1:D5, 2, 0)'], - ['=INDEX(B1:D5,,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('should work for scalars too', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - ['=INDEX(A1, 1, 1)'], - ['=INDEX(42, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('foo') - expect(engine.getCellValue(adr('A3'))).toEqual(42) - }) - - it('should assume first column if no last argument', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ['=INDEX(A1:B2, 2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) -}) diff --git a/test/unit/interpreter/function-int.spec.ts b/test/unit/interpreter/function-int.spec.ts deleted file mode 100644 index 1aa6d80128..0000000000 --- a/test/unit/interpreter/function-int.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function INT', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=INT()', '=INT(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=INT(1.3)', '=INT(1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=INT(-1.3)', '=INT(-1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-1) - expect(engine.getCellValue(adr('B1'))).toBe(-1) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=INT("42.3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(42) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=INT(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-interval.spec.ts b/test/unit/interpreter/function-interval.spec.ts deleted file mode 100644 index fd5e9f5da7..0000000000 --- a/test/unit/interpreter/function-interval.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function INTERVAL', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=INTERVAL("foo")', '=INTERVAL("12/30/2018")', '=INTERVAL(1, 2)', '=INTERVAL()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([['=INTERVAL(0)', '=INTERVAL(10000000)', '=INTERVAL(365.1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('PT') - expect(engine.getCellValue(adr('B1'))).toEqual('P3M25DT17H46M40S') - expect(engine.getCellValue(adr('C1'))).toEqual('PT6M5S') - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=INTERVAL("31/12/1899")', '=INTERVAL("01/01/1900")', '=INTERVAL("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual('PT1S') - expect(engine.getCellValue(adr('B1'))).toEqual('PT2S') - expect(engine.getCellValue(adr('C1'))).toEqual('PT12H4M25S') - }) - - it('use datenumber coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=INTERVAL(TRUE())'], - ['=INTERVAL("1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('PT1S') - expect(engine.getCellValue(adr('A2'))).toEqual('PT1S') - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=INTERVAL(NA())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-ipmt.spec.ts b/test/unit/interpreter/function-ipmt.spec.ts deleted file mode 100644 index 06105395bf..0000000000 --- a/test/unit/interpreter/function-ipmt.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function IPMT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=IPMT(1, 1)', '=IPMT(1, 1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=IPMT(1%, 12, 360, 100000)', '=IPMT(1%, 12, 360, 100000, 30000)', '=IPMT(1%, 12, 360, 100000, 30000, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-996.690428219826) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-995.697556685774) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(-985.839165035419) - }) -}) diff --git a/test/unit/interpreter/function-isbinary.spec.ts b/test/unit/interpreter/function-isbinary.spec.ts deleted file mode 100644 index a35200ec22..0000000000 --- a/test/unit/interpreter/function-isbinary.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('Function ISBINARY', () => { - it('should return true for binary numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISBINARY("1010")', '=ISBINARY(1001)', '=ISBINARY(010)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - }) - - it('should return false otherwise', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISBINARY("foo")', '=ISBINARY(123)', '=ISBINARY(TRUE())'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - }) -}) diff --git a/test/unit/interpreter/function-isblank.spec.ts b/test/unit/interpreter/function-isblank.spec.ts deleted file mode 100644 index 61038d6c53..0000000000 --- a/test/unit/interpreter/function-isblank.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISBLANK', () => { - it('should return true for references to empty cells', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=ISBLANK(A1)', '=ISBLANK(A2)'], - ['=A1'], - ]) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - }) - - it('should return false for empty string', () => { - const engine = HyperFormula.buildFromArray([['', '=ISBLANK(A1)']]) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - }) - - it('should return false if it is not reference to empty cell', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=ISBLANK("")', '=ISBLANK(4)', '=ISBLANK(CONCATENATE(A1,A1))'], - ]) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISBLANK(A3, A2)', '=ISBLANK()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('no error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISBLANK(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['0'], - [null], - [null], - ['=ISBLANK(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-iserr.spec.ts b/test/unit/interpreter/function-iserr.spec.ts deleted file mode 100644 index a0d61397fb..0000000000 --- a/test/unit/interpreter/function-iserr.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISERR', () => { - it('should return true for common errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISERR(1/0)', '=ISERR(FOO())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - }) - - it('should return false for #N/A!', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISERR(TRUE(1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('should return false for valid formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISERR(1)', '=ISERR(TRUE())', '=ISERR("foo")', '=ISERR(ISERR(1/0))', '=ISERR(A1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - expect(engine.getCellValue(adr('E1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISERR(1, 2)', '=ISERR()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/1'], - ['=4/0'], - ['=4/2'], - ['=ISERR(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-iserror.spec.ts b/test/unit/interpreter/function-iserror.spec.ts deleted file mode 100644 index 4095ca4feb..0000000000 --- a/test/unit/interpreter/function-iserror.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISERROR', () => { - it('should return true for common errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISERROR(1/0)', '=ISERROR(FOO())', '=ISERROR(TRUE(1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - }) - - it('should return false for valid formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISERROR(1)', '=ISERROR(TRUE())', '=ISERROR("foo")', '=ISERROR(ISERROR(1/0))', '=ISERROR(A1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - expect(engine.getCellValue(adr('E1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISERROR(1, 2)', '=ISERROR()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/1'], - ['=4/0'], - ['=4/2'], - ['=ISERROR(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-iseven.spec.ts b/test/unit/interpreter/function-iseven.spec.ts deleted file mode 100644 index f6ee0c8639..0000000000 --- a/test/unit/interpreter/function-iseven.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISEVEN', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISEVEN()', '=ISEVEN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISEVEN(1)', '=ISEVEN(2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISEVEN("42")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=ISEVEN(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-isformula.spec.ts b/test/unit/interpreter/function-isformula.spec.ts deleted file mode 100644 index aa65579c52..0000000000 --- a/test/unit/interpreter/function-isformula.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISFORMULA', () => { - it('should return true for cell with formula', () => { - const engine = HyperFormula.buildFromArray([ - ['=A1', '=ISFORMULA(A1)'] - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(true) - }) - - it('should return false for cell without formula', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', '=ISFORMULA(A1)', '=ISFORMULA(A2)'] - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - }) - - it('should work with start of a range', () => { - const engine = HyperFormula.buildFromArray([ - ['=A1', 2, '=ISFORMULA(A1:A2)', '=ISFORMULA(B1:B2)'] - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(true) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - }) - - it('should propagate error', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISFORMULA(1/0)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return NA otherwise', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISFORMULA()', '=ISFORMULA(A1, A2)', '=ISFORMULA("foo")', '=ISFORMULA(42)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - }) - - it('should work for itself', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISFORMULA(A1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - }) - - it('should collect dependencies of inner function and return argument type error', () => { - const engine = HyperFormula.buildFromArray([ - ['=SIN(1)'], - ['=ISFORMULA(SUM(A1,A3))'], - ['=SIN(1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - }) - - it('should propagate error of inner function', () => { - const engine = HyperFormula.buildFromArray([ - ['=1/0'], - ['=ISFORMULA(SUM(A1, A3))'], - ['=1/0'] - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return #CYCLE! when cyclic reference occurs not directly in COLUMN', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISFORMULA(SUM(A1))'], - ['=ISFORMULA(A1+A2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) -}) diff --git a/test/unit/interpreter/function-islogical.spec.ts b/test/unit/interpreter/function-islogical.spec.ts deleted file mode 100644 index c7e43aa8cb..0000000000 --- a/test/unit/interpreter/function-islogical.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISLOGICAL', () => { - it('should return true for boolean', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISLOGICAL(1<1)', '=ISLOGICAL(ISLOGICAL(A1))', '=ISLOGICAL(A2)'], - [false], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - }) - - it('should return false for non-boolean', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISLOGICAL(-0)', '=ISLOGICAL(A2)', '=ISLOGICAL("foo")'], - [null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISLOGICAL(1, 2)', '=ISLOGICAL()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/1'], - ['=4/0'], - ['=4/2'], - ['=ISLOGICAL(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-isna.spec.ts b/test/unit/interpreter/function-isna.spec.ts deleted file mode 100644 index c83ea192b1..0000000000 --- a/test/unit/interpreter/function-isna.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISNA', () => { - it('should return true for #NA! error', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE(1)', '=ISNA(A1)', '=ISNA(TRUE(1))'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - }) - - it('should return false for other values', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNA(1)', '=ISNA(TRUE())', '=ISNA("foo")', '=ISNA(A1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNA(1, 2)', '=ISNA()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE(1)'], - ['=TRUE(1)'], - ['=ISNA(A1:A2)'], - ]) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-isnontext.spec.ts b/test/unit/interpreter/function-isnontext.spec.ts deleted file mode 100644 index 996e2bd19f..0000000000 --- a/test/unit/interpreter/function-isnontext.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISNONTEXT', () => { - it('should return false for text', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNONTEXT("abcd")', '=ISNONTEXT(A2)'], - ['abcd'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - }) - - it('should return true for nontext', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNONTEXT(-0)', '=ISNONTEXT(A2)', '=ISNONTEXT(1<1)'], - [null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNONTEXT(1, 2)', '=ISNONTEXT()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/1'], - ['=4/0'], - ['=4/2'], - ['=ISNONTEXT(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-isnumber.spec.ts b/test/unit/interpreter/function-isnumber.spec.ts deleted file mode 100644 index 763c2aafec..0000000000 --- a/test/unit/interpreter/function-isnumber.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISNUMBER', () => { - it('should return true for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNUMBER(1)', '=ISNUMBER(-0)', '=ISNUMBER(1+1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('C1'))).toEqual(true) - }) - - it('should return false for nonnumbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNUMBER(1<1)', '=ISNUMBER(A2)', '=ISNUMBER("foo")'], - [null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISNUMBER(1, 2)', '=ISNUMBER()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) -}) diff --git a/test/unit/interpreter/function-isodd.spec.ts b/test/unit/interpreter/function-isodd.spec.ts deleted file mode 100644 index c33872cce4..0000000000 --- a/test/unit/interpreter/function-isodd.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISODD', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISODD()', '=ISODD(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISODD(1)', '=ISODD(2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISODD("42")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=ISODD(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-isoweeknum.spec.ts b/test/unit/interpreter/function-isoweeknum.spec.ts deleted file mode 100644 index 12b2baea71..0000000000 --- a/test/unit/interpreter/function-isoweeknum.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISOWEEKNUM', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM(1, 2)'], - ['=ISOWEEKNUM()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for wrong value of args', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM(-1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should work for strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM("02/08/2020")'], - ['=ISOWEEKNUM("02/08/2017")'], - ['=ISOWEEKNUM("01/01/2020")'], - ['=ISOWEEKNUM("01/01/2017")'], - ['=ISOWEEKNUM("01/01/2016")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('A2'))).toEqual(31) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(52) - expect(engine.getCellValue(adr('A5'))).toEqual(53) - }) - - it('should work for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM(0)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(52) - }) - - it('should work for strings with different nullDate', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM("02/08/2020")'], - ['=ISOWEEKNUM("02/08/2017")'], - ['=ISOWEEKNUM("01/01/2020")'], - ['=ISOWEEKNUM("01/01/2017")'], - ['=ISOWEEKNUM("01/01/2016")'], - ], {nullDate: {day: 20, month: 10, year: 1920}}) - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('A2'))).toEqual(31) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(52) - expect(engine.getCellValue(adr('A5'))).toEqual(53) - }) - - it('should work for strings with compatibility mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM("02/08/2020")'], - ['=ISOWEEKNUM("02/08/2017")'], - ['=ISOWEEKNUM("01/01/2020")'], - ['=ISOWEEKNUM("01/01/2017")'], - ['=ISOWEEKNUM("01/01/2016")'], - ], {leapYear1900: true}) - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('A2'))).toEqual(31) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(52) - expect(engine.getCellValue(adr('A5'))).toEqual(53) - }) - it('should work for strings with compatibility mode and different nullDate', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISOWEEKNUM("02/08/2020")'], - ['=ISOWEEKNUM("02/08/2017")'], - ['=ISOWEEKNUM("01/01/2020")'], - ['=ISOWEEKNUM("01/01/2017")'], - ['=ISOWEEKNUM("01/01/2016")'], - ], {leapYear1900: true, nullDate: {day: 20, month: 10, year: 1920}}) - expect(engine.getCellValue(adr('A1'))).toEqual(31) - expect(engine.getCellValue(adr('A2'))).toEqual(31) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(52) - expect(engine.getCellValue(adr('A5'))).toEqual(53) - }) -}) diff --git a/test/unit/interpreter/function-ispmt.spec.ts b/test/unit/interpreter/function-ispmt.spec.ts deleted file mode 100644 index 977f096d90..0000000000 --- a/test/unit/interpreter/function-ispmt.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISPMT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISPMT(1, 1, 1)', '=ISPMT(1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISPMT(1, 1, 10, 1)', '=ISPMT(1, 1, 0, 1)', '=ISPMT(1, -1, 1, 1)', '=ISPMT(-1, -1, 1, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-0.9) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C1'))).toEqual(-2) - expect(engine.getCellValue(adr('D1'))).toEqual(-2) - }) -}) diff --git a/test/unit/interpreter/function-isref.spec.ts b/test/unit/interpreter/function-isref.spec.ts deleted file mode 100644 index 37a6532faa..0000000000 --- a/test/unit/interpreter/function-isref.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISREF', () => { - it('should return true for #REF!', () => { - const engine = HyperFormula.buildFromArray([ - ['=#REF!', '=ISREF(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(true) - }) - - it('should return true for #CYCLE!', () => { - const engine = HyperFormula.buildFromArray([ - ['=A1', '=ISREF(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(true) - }) - - it('should return false for other values', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISREF(1)', '=ISREF(TRUE())', '=ISREF("foo")', '=ISREF(A1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - expect(engine.getCellValue(adr('D1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISREF(1, 2)', '=ISREF()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - // Inconsistency with Product 1 - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['=A1'], - ['=A2'], - [], - ['=ISREF(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - // Inconsistency with Product 1 - it('returns #CYCLE! for itself', () => { - /* TODO can we handle such case correctly? */ - const engine = HyperFormula.buildFromArray([ - ['=ISREF(A1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) -}) diff --git a/test/unit/interpreter/function-istext.spec.ts b/test/unit/interpreter/function-istext.spec.ts deleted file mode 100644 index a0682e4682..0000000000 --- a/test/unit/interpreter/function-istext.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ISTEXT', () => { - it('should return true for text', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISTEXT("abcd")', '=ISTEXT(A2)'], - ['abcd'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - }) - - it('should return false for nontext', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISTEXT(-0)', '=ISTEXT(A2)', '=ISTEXT(1<1)'], - [null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(false) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('C1'))).toEqual(false) - }) - - it('takes exactly one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ISTEXT(1, 2)', '=ISTEXT()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/1'], - ['=4/0'], - ['=4/2'], - ['=ISTEXT(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-large.spec.ts b/test/unit/interpreter/function-large.spec.ts deleted file mode 100644 index 1372469f98..0000000000 --- a/test/unit/interpreter/function-large.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LARGE', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=LARGE(1)'], - ['=LARGE(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=LARGE(1, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=LARGE(A2:D2, 0)', '=LARGE(A2:D2, 1)', '=LARGE(A2:D2, 2)', '=LARGE(A2:D2, 3)', '=LARGE(A2:D2, 4)', '=LARGE(A2:D2, 5)'], - [1, 4, 2, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('C1'))).toEqual(4) - expect(engine.getCellValue(adr('D1'))).toEqual(2) - expect(engine.getCellValue(adr('E1'))).toEqual(1) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('should ignore non-numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=LARGE(A2:D2, 0)', '=LARGE(A2:D2, 1)', '=LARGE(A2:D2, 2)', '=LARGE(A2:D2, 3)'], - [1, 4, true, 'abcd'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=LARGE(A2:D2, 0)', '=LARGE(A2:D2, 1)', '=LARGE(A2:D2, 2)', '=LARGE(A2:D2, 3)'], - [1, 4, '=NA()', 'abcd'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should truncate second arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=LARGE(A2:D2, 0.9)', '=LARGE(A2:D2, 1.9)', '=LARGE(A2:D2, 2.9)', '=LARGE(A2:D2, 3.9)', '=LARGE(A2:D2, 4.9)', '=LARGE(A2:D2, 5.9)'], - [1, 4, 2, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('C1'))).toEqual(4) - expect(engine.getCellValue(adr('D1'))).toEqual(2) - expect(engine.getCellValue(adr('E1'))).toEqual(1) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('should work for non-ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=LARGE(1,0)', '=LARGE(1,1)', '=LARGE(1,2)', '=LARGE(TRUE(),1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - //inconsistency with product #2 - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-lcm.spec.ts b/test/unit/interpreter/function-lcm.spec.ts deleted file mode 100644 index b479dedad4..0000000000 --- a/test/unit/interpreter/function-lcm.spec.ts +++ /dev/null @@ -1,117 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LCM', () => { - it('checks required number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('computes correct answer for two args', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(2*3*5, 3*5*7)', '=LCM(0, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(2 * 3 * 5 * 7) - expect(engine.getCellValue(adr('B1'))).toBe(0) - }) - - it('computes correct answer for more than two args', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(2*3*5, 3*5*7, 2*5*7)', '=LCM(100, 101, 102, 103, 104)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(2 * 3 * 5 * 7) - expect(engine.getCellValue(adr('B1'))).toBe(1379437800) - }) - - it('works with zeroes', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(2*3*5, 3*5*7, 2*5*7, 0, 0, 0)', '=LCM(0, 0, 100, 101, 102, 103, 104, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBe(0) - }) - - it('accepts single arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(1)', '=LCM(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(0) - }) - - it('handles overflow', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(1000000, 1000001, 1000002, 1000003)'], - ]) - - //inconsistency with product #1 - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('coerces to number', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM("4",2)'], - ['=LCM(B2:C2)', '\'4', 2], - ['=LCM(FALSE(),4)'], - ['=LCM(B4:C4)', false, 4], - ['=LCM(,4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(4) - expect(engine.getCellValue(adr('A2'))).toBe(4) - expect(engine.getCellValue(adr('A3'))).toBe(0) - expect(engine.getCellValue(adr('A4'))).toBe(0) - expect(engine.getCellValue(adr('A5'))).toBe(0) - }) - - it('ignores non-coercible values', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(B1:C1)', 'abcd', 4], - ['=LCM(B2:C2)', null, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(4) - expect(engine.getCellValue(adr('A2'))).toBe(4) - }) - - it('throws error for non-coercible values', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM("abcd",4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(-1, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('truncates numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(B1:C1)', 5.5, 10], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(10) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=LCM(NA(),4)'], - ['=LCM(B2:C2)', '=NA()', 4], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-left.spec.ts b/test/unit/interpreter/function-left.spec.ts deleted file mode 100644 index 42d5cb9cce..0000000000 --- a/test/unit/interpreter/function-left.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LEFT', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEFT()'], - ['=LEFT("foo", 1, 2)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return VALUE when wrong type of second parameter', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEFT("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work with empty argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEFT(, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - }) - - it('should return one character by default', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEFT("bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('b') - }) - - it('should return VALUE when second parameter is less than 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEFT("foo", -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NegativeLength)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEFT("", 4)'], - ['=LEFT("bar", 0)'], - ['=LEFT("bar", 1)'], - ['=LEFT("bar", 3)'], - ['=LEFT("bar", 4)'], - ['=LEFT(123, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('') - expect(engine.getCellValue(adr('A3'))).toEqual('b') - expect(engine.getCellValue(adr('A4'))).toEqual('bar') - expect(engine.getCellValue(adr('A5'))).toEqual('bar') - expect(engine.getCellValue(adr('A6'))).toEqual('12') - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEFT(10, 1)'], - ['=LEFT(5+5, 1)'], - ['=LEFT(TRUE(), 1)'], - ['=LEFT("010", 1)'], - ['=LEFT(B5, 1)', "'010"], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('1') - expect(engine.getCellValue(adr('A3'))).toEqual('T') - expect(engine.getCellValue(adr('A4'))).toEqual('0') - expect(engine.getCellValue(adr('A5'))).toEqual('0') - }) -}) diff --git a/test/unit/interpreter/function-len.spec.ts b/test/unit/interpreter/function-len.spec.ts deleted file mode 100644 index dd66ba5e78..0000000000 --- a/test/unit/interpreter/function-len.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LEN', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEN()'], - ['=LEN("foo", "bar")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEN("foo")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=LEN(1)'], - ['=LEN(5+5)'], - ['=LEN(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - }) -}) diff --git a/test/unit/interpreter/function-ln.spec.ts b/test/unit/interpreter/function-ln.spec.ts deleted file mode 100644 index c8221f67ef..0000000000 --- a/test/unit/interpreter/function-ln.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LN', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=LN(2.718281828459045)']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=LN("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('for zero', () => { - const engine = HyperFormula.buildFromArray([['=LN(0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('for negative arguments', () => { - const engine = HyperFormula.buildFromArray([['=LN(-42)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=LN()', '=LN(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="2.718281828459045"', '=LN(A1)'], - ['', '=LN(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBe(1) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=LN(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-log.spec.ts b/test/unit/interpreter/function-log.spec.ts deleted file mode 100644 index 460dcdecb2..0000000000 --- a/test/unit/interpreter/function-log.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LOG', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=LOG(4, 2)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(2) - }) - - it('logarithmic base has default', () => { - const engine = HyperFormula.buildFromArray([['=LOG(10)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOG("foo", 42)'], - ['=LOG(42, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('for zero', () => { - const engine = HyperFormula.buildFromArray([['=LOG(0, 42)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('for negative value', () => { - const engine = HyperFormula.buildFromArray([['=LOG(-42, 42)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('for zero base', () => { - const engine = HyperFormula.buildFromArray([['=LOG(42, 0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('for 1 base', () => { - const engine = HyperFormula.buildFromArray([['=LOG(42, 1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('for negative base', () => { - const engine = HyperFormula.buildFromArray([['=LOG(42, -42)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=LOG()', '=LOG(42, 42, 42)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="10"', '=LOG(A1, 10)', '=LOG(10, A1)'], - ['', '=LOG(A2, 42)', '=LOG(42, 0)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBe(1) - expect(engine.getCellValue(adr('C1'))).toBe(1) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOG(4/0, 42)'], - ['=LOG(42, 4/0)'], - ['=LOG(4/0, FOOBAR())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-log10.spec.ts b/test/unit/interpreter/function-log10.spec.ts deleted file mode 100644 index f5efebb7cc..0000000000 --- a/test/unit/interpreter/function-log10.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LOG10', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=LOG10(10)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=LOG10("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('for zero', () => { - const engine = HyperFormula.buildFromArray([['=LOG10(0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('for negative arguments', () => { - const engine = HyperFormula.buildFromArray([['=LOG10(-42)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=LOG10()', '=LOG10(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="10"', '=LOG10(A1)'], - ['', '=LOG10(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBe(1) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOG10(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-lognorm.dist.spec.ts b/test/unit/interpreter/function-lognorm.dist.spec.ts deleted file mode 100644 index 0de52621ff..0000000000 --- a/test/unit/interpreter/function-lognorm.dist.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LOGNORM.DIST', () => { - //in product #1, this function takes 3 arguments - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.DIST(1, 2, 3)'], - ['=LOGNORM.DIST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - //in product #1, this function takes 3 arguments - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.DIST("foo", 2, 3, TRUE())'], - ['=LOGNORM.DIST(1, "baz", 3, TRUE())'], - ['=LOGNORM.DIST(1, 2, "baz", TRUE())'], - ['=LOGNORM.DIST(1, 2, 3, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - //in product #1, this function takes 3 arguments - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.DIST(0.1, 1, 2, TRUE())'], - ['=LOGNORM.DIST(0.5, 2, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0493394267528022, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.250382425968177, 6) - }) - - //in product #1, this function takes 3 arguments - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.DIST(0.1, 1, 2, FALSE())'], - ['=LOGNORM.DIST(0.5, 2, 4, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.510234855730895, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.159017142514074, 6) - }) - - //in product #1, this function takes 3 arguments - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.DIST(0.01, 0, 0.01, FALSE())'], - ['=LOGNORM.DIST(0, 0, 0.01, FALSE())'], - ['=LOGNORM.DIST(0.01, 0, 0, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-lognorm.inv.spec.ts b/test/unit/interpreter/function-lognorm.inv.spec.ts deleted file mode 100644 index 8fa25e1e14..0000000000 --- a/test/unit/interpreter/function-lognorm.inv.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LOGNORM.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.INV(1, 2)'], - ['=LOGNORM.INV(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.INV("foo", 2, 3)'], - ['=LOGNORM.INV(0.5, "baz", 3)'], - ['=LOGNORM.INV(0.5, 2, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.INV(0.1, 1, 2)'], - ['=LOGNORM.INV(0.5, 2, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.209485002124057, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(7.38905609893065, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOGNORM.INV(0.01, 0, 0.01)'], - ['=LOGNORM.INV(0, 0, 0.01)'], - ['=LOGNORM.INV(0.01, 0, 0)'], - ['=LOGNORM.INV(0.99, 0, 0.01)'], - ['=LOGNORM.INV(1, 0, 0.01)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.977005029803317, 6) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(1.0235361840474, 6) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-lower.spec.ts b/test/unit/interpreter/function-lower.spec.ts deleted file mode 100644 index e8c7825ca3..0000000000 --- a/test/unit/interpreter/function-lower.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function LOWER', () => { - it('should take one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOWER()'], - ['=LOWER("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should convert text to lowercase', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOWER("")'], - ['=LOWER(B1)'], - ['=LOWER("foo")'], - ['=LOWER("FOO")'], - ['=LOWER("BaR")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('') - expect(engine.getCellValue(adr('A3'))).toEqual('foo') - expect(engine.getCellValue(adr('A4'))).toEqual('foo') - expect(engine.getCellValue(adr('A5'))).toEqual('bar') - }) - - it('should coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOWER(TRUE())'], - ['=LOWER(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('true') - expect(engine.getCellValue(adr('A2'))).toEqual('0') - }) -}) diff --git a/test/unit/interpreter/function-match.spec.ts b/test/unit/interpreter/function-match.spec.ts deleted file mode 100644 index ab398f6fba..0000000000 --- a/test/unit/interpreter/function-match.spec.ts +++ /dev/null @@ -1,758 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {DependencyGraph} from '../../../src/DependencyGraph' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, resetSpy} from '../testUtils' - -describe('Function MATCH', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1)'], - ['=MATCH(1, B1:B3, 0, 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('validates number of arguments when array arithmetics is on', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1)'], - ['=MATCH(1, B1:B3, 0, 42)'], - ], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('validates that 1st argument is number, string or boolean', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(C2:C3, B1:B1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('2nd argument can be a scalar', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(42, 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('validates that 3rd argument is number', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(0, B1:B1, "a")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('validates that 3rd argument is in [-1, 0, 1]', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(0, B1:B1, -2)'], - ['=MATCH(0, B1:B1, 0.5)'], - ['=MATCH(0, B1:B1, 100)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - }) - - it('should propagate errors properly', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1/0, B1:B1)'], - ['=MATCH(1, B1:B1, 1/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when MatchType is empty defaults to 1 (returns lower bound)', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:A5)'], - ['100'], - ['110'], - ['120'], - ['130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - describe('when MatchType = 0', () => { - describe('when search range is vertical', () => { - it('works when the result is in the first cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A2:A5, 0)'], - ['103'], - ['200'], - ['200'], - ['200'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('works when the result is in the last cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A2:A5, 0)'], - ['200'], - ['200'], - ['200'], - ['103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns the relative position in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(102, A6:A9, 0)'], - [''], - [''], - [''], - [''], - ['100'], - ['101'], - ['102'], - ['103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('returns the first matching result', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A2:A5, 0)'], - ['200'], - ['103'], - ['103'], - ['200'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('doesn\'t return result from outside the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A3:A6, 0)'], - ['103', '103'], - ['200', '103'], - ['200', '103'], - ['200', '103'], - ['200', '103'], - ['103', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - }) - - describe('when search range is horizontal', () => { - it('works when the result is in first cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A2:D2, 0)'], - ['103', '200', '200', '200'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('works when the result is in the last cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A2:D2, 0)'], - ['200', '200', '200', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns the relative position in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(102, E2:H2, 0)'], - ['', '', '', '', '100', '101', '102', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('returns the first matching result', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A2:D2, 0)'], - ['200', '103', '103', '200'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('doesn\'t return result from outside the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, B2:E2, 0)'], - ['103', '200', '200', '200', '200', '103'], - ['103', '103', '103', '103', '103', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - }) - - it('uses indexOf', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const spy = spyOn(DependencyGraph.prototype as any, 'computeListOfValuesInRange') - resetSpy(spy) - - const engine = HyperFormula.buildFromArray([ - ['=MATCH(400, A2:A5, 0)'], - ['100'], - ['200'], - ['300'], - ['400'], - ['500'], - ]) - - expect(spy).toHaveBeenCalled() - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('works for strings, is not case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH("A", A2:A5, 0)'], - ['a'], - ['A'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('works for strings, is not case sensitive even if config defines case sensitivity', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH("A", A2:A5, 0)'], - ['a'], - ['A'], - ], { caseSensitive: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('works with dates', () => { - const engine = HyperFormula.buildFromArray( - [ - ['01/04/2012', '01/01/2012', '=MATCH(B1, A1:A4, 0)'], - ['01/01/2012', '01/02/2012', '=MATCH(B2, A1:A4, 0)'], - ['01/02/2012'], - ['01/03/2012'], - ] - ) - expect(engine.getCellValue(adr('C1'))).toEqual(2) - expect(engine.getCellValue(adr('C2'))).toEqual(3) - }) - }) - - describe('when MatchType = 1', () => { - describe('when search range is vertical', () => { - it('returns the lower bound if the range is sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:A5, 1)'], - ['100'], - ['110'], - ['120'], - ['130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('returns the exact match if present in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(120, A2:A5, 1)'], - ['100'], - ['110'], - ['120'], - ['130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('returns the last match if there are duplicates in the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(110, A2:A5, 1)'], - ['110'], - ['110'], - ['110'], - ['110'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns the last value if all are smaller than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1000, A2:A5, 1)'], - ['100'], - ['110'], - ['120'], - ['130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns an error if all are greater than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:A5, 1)'], - ['200'], - ['210'], - ['220'], - ['230'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('returns the relative position in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A6:A9, 1)'], - [''], - [''], - [''], - [''], - ['100'], - ['110'], - ['120'], - ['130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('doesn\'t return result from outside the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A3:A6, 1)'], - ['103', '103'], - ['200', '103'], - ['200', '103'], - ['200', '103'], - ['200', '103'], - ['103', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - }) - - describe('when search range is horizontal', () => { - it('returns the lower bound if the range is sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:D2, 1)'], - ['100', '110', '120', '130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('returns the exact match if present in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(120, A2:D2, 1)'], - ['100', '110', '120', '130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('returns the last match if there are duplicates in the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(110, A2:D2, 1)'], - ['110', '110', '110', '110'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns the last value if all are smaller than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1000, A2:D2, 1)'], - ['100', '110', '120', '130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns an error if all are greater than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1, A2:D2, 1)'], - ['100', '110', '120', '130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('returns the relative position in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(112, E2:H2, 1)'], - ['', '', '', '', '100', '110', '120', '130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('doesn\'t return result from outside the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, B2:E2, 1)'], - ['103', '200', '200', '200', '200', '103'], - ['103', '103', '103', '103', '103', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - }) - - it('works for strings, is not case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH("C", A2:A5, 1)'], - ['a'], - ['b'], - ['d'], - ['e'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('works for strings, is not case sensitive even if config defines case sensitivity', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH("C", A2:A5, 1)'], - ['a'], - ['b'], - ['d'], - ['e'], - ], { caseSensitive: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('works with dates', () => { - const engine = HyperFormula.buildFromArray( - [ - ['01/01/2012', '01/02/2012', '=MATCH(B1, A1:A4, 1)'], - ['01/02/2012', '10/02/2012', '=MATCH(B2, A1:A4, 1)'], - ['01/03/2012'], - ['01/04/2012'], - ] - ) - expect(engine.getCellValue(adr('C1'))).toEqual(2) - expect(engine.getCellValue(adr('C2'))).toEqual(2) - }) - - it('uses binary search', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const spy = spyOn(DependencyGraph.prototype as any, 'computeListOfValuesInRange') - resetSpy(spy) - - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:A5, 1)'], - ['100'], - ['110'], - ['120'], - ['130'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(spy).not.toHaveBeenCalled() - }) - }) - - describe('when MatchType = -1', () => { - describe('when search range is vertical', () => { - it('returns the upper bound if the range is sorted descending', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:A5, -1)'], - ['130'], - ['120'], - ['110'], - ['100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('returns the exact match if present in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(120, A2:A5, -1)'], - ['130'], - ['120'], - ['110'], - ['100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('returns the last match if there are duplicates in the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(110, A2:A5, -1)'], - ['110'], - ['110'], - ['110'], - ['110'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns the last value if all are greater than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1, A2:A5, -1)'], - ['130'], - ['120'], - ['110'], - ['100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns an error if all are smaller than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1000, A2:A5, -1)'], - ['130'], - ['120'], - ['110'], - ['100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('returns the relative position in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A6:A9, -1)'], - [''], - [''], - [''], - [''], - ['130'], - ['120'], - ['110'], - ['100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('doesn\'t return result from outside the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, A3:A6, -1)'], - ['103', '103'], - ['100', '103'], - ['100', '103'], - ['100', '103'], - ['100', '103'], - ['103', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - }) - - describe('when search range is horizontal', () => { - it('returns the lower bound if the range is sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:D2, -1)'], - ['130', '120', '110', '100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('returns the exact match if present in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(120, A2:D2, -1)'], - ['130', '120', '110', '100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('returns the last match if there are duplicates in the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(110, A2:D2, -1)'], - ['110', '110', '110', '110'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns the last value if all are greater than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1, A2:D2, -1)'], - ['130', '120', '110', '100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('returns an error if all are smaller than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(1000, A2:D2, -1)'], - ['130', '120', '110', '100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('returns the relative position in the range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(112, E2:H2, -1)'], - ['', '', '', '', '130', '120', '110', '100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('doesn\'t return result from outside the search range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(103, B2:E2, -1)'], - ['103', '100', '100', '100', '100', '103'], - ['103', '103', '103', '103', '103', '103'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - }) - - it('works for strings, is not case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH("C", A2:A5, -1)'], - ['e'], - ['d'], - ['b'], - ['a'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('works for strings, is not case sensitive even if config defines case sensitivity', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH("C", A2:A5, -1)'], - ['e'], - ['d'], - ['b'], - ['a'], - ], { caseSensitive: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('works with dates', () => { - const engine = HyperFormula.buildFromArray( - [ - ['01/04/2012', '01/02/2012', '=MATCH(B1, A1:A4, -1)'], - ['01/03/2012', '10/02/2012', '=MATCH(B2, A1:A4, -1)'], - ['01/02/2012'], - ['01/01/2012'], - ] - ) - expect(engine.getCellValue(adr('C1'))).toEqual(3) - expect(engine.getCellValue(adr('C2'))).toEqual(2) - }) - - it('uses binary search', () => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const spy = spyOn(DependencyGraph.prototype as any, 'computeListOfValuesInRange') - resetSpy(spy) - - const engine = HyperFormula.buildFromArray([ - ['=MATCH(113, A2:A5, -1)'], - ['130'], - ['120'], - ['110'], - ['100'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(spy).not.toHaveBeenCalled() - }) - }) - - it('should coerce empty arg to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['-5'], - ['-2'], - ['0'], - ['2'], - ['5'], - ['=MATCH(0, A1:A5)'], - ['=MATCH(, A1:A5)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual(3) - expect(engine.getCellValue(adr('A7'))).toEqual(3) - }) - - it('should coerce empty arg to zero when useColumnIndex = false', () => { - const engine = HyperFormula.buildFromArray([ - ['=MATCH(, A2:A4, 0)'], - [1], - [3], - [0], - ], {useColumnIndex: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should return NA when range is not a single column or row', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '1'], - ['2', '3'], - ['=MATCH(0, A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA)) - }) - - describe('works with a range reference to an empty sheet', () => { - it('- cell range', () => { - const hf = HyperFormula.buildFromSheets({ - table1: [], - table2: [['=MATCH(0, table1!A1:A10)']], - }) - - expect(hf.getCellValue(adr('A1', 1))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('- column range', () => { - const hf = HyperFormula.buildFromSheets({ - table1: [[]], - table2: [['=MATCH(0, table1!A:A)']], - }) - - expect(hf.getCellValue(adr('A1', 1))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('- row range', () => { - const hf = HyperFormula.buildFromSheets({ - table1: [], - table2: [['=MATCH(0, table1!1:1)']], - }) - - expect(hf.getCellValue(adr('A1', 1))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('- column range (called from calculateFormula)', () => { - const hf = HyperFormula.buildFromArray([]) - - expect(hf.calculateFormula('=MATCH(0, Sheet1!A:A)', 0)).toEqualError(detailedError(ErrorType.NA)) - }) - - it('- column range (called from calculateFormula without explicit sheet reference)', () => { - const hf = HyperFormula.buildFromArray([]) - - expect(hf.calculateFormula('=MATCH(0, A:A)', 0)).toEqualError(detailedError(ErrorType.NA)) - }) - }) -}) diff --git a/test/unit/interpreter/function-max.spec.ts b/test/unit/interpreter/function-max.spec.ts deleted file mode 100644 index 06b7e938d4..0000000000 --- a/test/unit/interpreter/function-max.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('MAX', () => { - it('MAX with empty args', () => { - const engine = HyperFormula.buildFromArray([['=MAX()']]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('MAX with args', () => { - const engine = HyperFormula.buildFromArray([['=MAX(1, B1)', '3.14']]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(3.14) - }) - - it('MAX with range', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=MAX(A1:A3)']]) - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('MAX with mixed arguments', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=MAX(4,A1:A3)']]) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('doesnt do coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['foo'], - ['=TRUE()'], - ['=CONCATENATE("1","0")'], - ['=MAX(A1:A5)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual(2) - }) - - it('MAX of strings and -1', () => { - const engine = HyperFormula.buildFromArray([['foo'], ['bar'], ['-1'], ['=MAX(A1:A3)']]) - expect(engine.getCellValue(adr('A4'))).toEqual(-1) - }) - - it('MAX of empty value', () => { - const engine = HyperFormula.buildFromArray([['', '=MAX(A1)']]) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('MAX of empty value and some negative number', () => { - const engine = HyperFormula.buildFromArray([['', '-1', '=MAX(A1,B1)']]) - expect(engine.getCellValue(adr('C1'))).toEqual(-1) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=MAX(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(22) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=MAX(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-maxa.spec.ts b/test/unit/interpreter/function-maxa.spec.ts deleted file mode 100644 index b352558590..0000000000 --- a/test/unit/interpreter/function-maxa.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('MAXA', () => { - it('MAXA with empty args', () => { - const engine = HyperFormula.buildFromArray([['=MAXA()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('MAXA with args', () => { - const engine = HyperFormula.buildFromArray([['=MAXA(1, B1)', '3.14']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(3.14) - }) - - it('MAXA with range', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=MAXA(A1:A3)']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('does only boolean coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['="42"', '=MAXA(A1)'], - ['=TRUE()', '=MAXA(A2)'], - ['=FALSE()', '=MAXA(A3)'], - ['="TRUE"', '=MAXA(A4)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('B2'))).toEqual(1) - expect(engine.getCellValue(adr('B3'))).toEqual(0) - expect(engine.getCellValue(adr('B4'))).toEqual(0) - }) - - it('MAXA of strings and -1', () => { - const engine = HyperFormula.buildFromArray([['foo'], ['bar'], ['-1'], ['=MAXA(A1:A3)']]) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('MAXA of empty value', () => { - const engine = HyperFormula.buildFromArray([['', '=MAXA(A1)']]) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('MAXA of empty value and some negative number', () => { - const engine = HyperFormula.buildFromArray([ - ['', '-1', '=MAXA(A1,B1)'], - [null, '-1', '=MAXA(A2,B2)'], - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - expect(engine.getCellValue(adr('C2'))).toEqual(-1) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=MAXA(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(22) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=MAXA(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-maxifs.spec.ts b/test/unit/interpreter/function-maxifs.spec.ts deleted file mode 100644 index 7543857fac..0000000000 --- a/test/unit/interpreter/function-maxifs.spec.ts +++ /dev/null @@ -1,259 +0,0 @@ -import {HyperFormula, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectArrayWithSameContent} from '../testUtils' -import {DateTimeHelper} from '../../../src/DateTimeHelper' -import {Config} from '../../../src/Config' - -describe('Function MAXIFS - argument validations and combinations', () => { - it('requires odd number of arguments, but at least 3', () => { - const engine = HyperFormula.buildFromArray([['=MAXIFS(C1, ">0")'], ['=MAXIFS(C1, ">0", B1, B1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('error when criterion unparsable', () => { - const engine = HyperFormula.buildFromArray([ - ['=MAXIFS(B1:B2, C1:C2, "> { - const engine = HyperFormula.buildFromArray([ - ['=MAXIFS(B1:C1, B2:D2, ">0")'], - ['=MAXIFS(B1, B2:D2, ">0")'], - ['=MAXIFS(B1:D1, B2, ">0")'], - ['=MAXIFS(B1:D1, B2:D2, ">0", B2:E2, ">0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('error when different height dimension of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MAXIFS(B1:B2, C1:C3, ">0")'], - ['=MAXIFS(B1, C1:C2, ">0")'], - ['=MAXIFS(B1:B2, C1, ">0")'], - ['=MAXIFS(B1:B2, C1:C2, ">0", C1:C3, ">0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('scalars are treated like singular arrays', () => { - const engine = HyperFormula.buildFromArray([['=MAXIFS(42, 10, ">1")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('should return 0 as max from an empty range', () => { - const engine = HyperFormula.buildFromArray([['=MAXIFS(42, -1, ">1")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=MAXIFS(4/0, 42, ">1")'], - ['=MAXIFS(0, 4/0, ">1")'], - ['=MAXIFS(0, 42, 4/0)'], - ['=MAXIFS(0, 4/0, FOOBAR())'], - ['=MAXIFS(4/0, FOOBAR(), ">1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works when arguments are just references', () => { - const engine = HyperFormula.buildFromArray([['2', '3'], ['=MAXIFS(B1, A1, ">1")']]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('works with numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['2', 'a'], - ['3', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('works with percents', () => { - const engine = HyperFormula.buildFromArray([ - ['2%', 'a'], - ['3%', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(.03) - }) - - it('works with currencies', () => { - const engine = HyperFormula.buildFromArray([ - ['$2', 'a'], - ['$3', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('works with dates', () => { - const dateHelper = new DateTimeHelper(new Config()) - - const engine = HyperFormula.buildFromArray([ - ['20/01/2020', 'a'], - ['30/01/2020', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(dateHelper.numberToSimpleDate(engine.getCellValue(adr('A3')) as number)).toEqual({ day: 30, month: 1, year: 2020 }) - }) - - it('strings are ignored', () => { - const engine = HyperFormula.buildFromArray([ - ['-1', 'a'], - ['abc', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(-1) - }) - - it('empty cells are ignored', () => { - const engine = HyperFormula.buildFromArray([ - ['-1', 'a'], - ['', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(-1) - }) - - it('booleans are ignored', () => { - const engine = HyperFormula.buildFromArray([ - ['-1', 'a'], - ['=TRUE()', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(-1) - }) - - it('max of empty cells is zero', () => { - const engine = HyperFormula.buildFromArray([ - ['', 'a'], - ['', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('max of strings is zero', () => { - const engine = HyperFormula.buildFromArray([ - ['abc', 'a'], - ['cba', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('max of booleans is zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', 'a'], - ['=FALSE()', 'a'], - ['=MAXIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('works with range values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '3', '5'], - ['1', '1', '7', '9'], - ['=MAXIFS(MMULT(C1:D2, C1:D2), MMULT(A1:B2, A1:B2), "=2")'], - ['=MAXIFS(MMULT(C1:D2, C1:D2), A1:B2, "=1")'], - ['=MAXIFS(C1:D2, MMULT(A1:B2, A1:B2), "=2")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(116) - expect(engine.getCellValue(adr('A4'))).toEqual(116) - expect(engine.getCellValue(adr('A5'))).toEqual(9) - }) - - it('works for mixed reference/range arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=MAXIFS(B1, A1:A1, ">1")'], - ['4', '5'], - ['=MAXIFS(B3:B3, A3, ">1")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('works when criterion arg is an inline array', () => { - const engine = HyperFormula.buildFromArray([[2, 'a'], [3, 'b'], ['=MAXIFS(A1:A2, B1:B2, {"a", "b"})']], { - useArrayArithmetic: true, - }) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('B3'))).toEqual(3) - }) -}) - -describe('Function MAXIFS - calcultions on more than one criteria', () => { - it('works for more than one criterion/range pair', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '100', '3'], - ['1', '101', '5'], - ['2', '102', '7'], - ['=MAXIFS(C1:C3, A1:A3, ">=1", B1:B3, "<102")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) -}) - -describe('Function MAXIFS - cache recalculation after cruds', () => { - it('recalculates MAXIFS if changes in the first range', () => { - const sheet = [['10', '10'], ['5', '6'], ['7', '8'], ['=MAXIFS(A1:B1, A2:B2, ">=5", A3:B3, ">=7")']] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), [['1', '3']]) - const newValues = changes.map(c => c.newValue) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - expectArrayWithSameContent(newValues, [1, 3, 3]) - }) - - it('recalculates MAXIFS if changes in one of the tested range', () => { - const sheet = [['20', '10'], ['5', '6'], ['7', '8'], ['=MAXIFS(A1:B1, A2:B2, ">=5", A3:B3, ">=7")']] - const engine = HyperFormula.buildFromArray(sheet) - expect(engine.getCellValue(adr('A4'))).toEqual(20) - - engine.setCellContents(adr('A3'), [['1', '7']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(10) - }) -}) diff --git a/test/unit/interpreter/function-median.spec.ts b/test/unit/interpreter/function-median.spec.ts deleted file mode 100644 index 51b68bbe1a..0000000000 --- a/test/unit/interpreter/function-median.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MEDIAN', () => { - it('single number', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('two numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1.5) - }) - - it('more numbers (odd)', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(3, 1, 2, 5, 7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('more numbers (even)', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(3, 4, 1, 2, 5, 7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3.5) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '5', '1'], - ['=MEDIAN(A1:C1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('propagates error from regular argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=MEDIAN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('propagates first error from range argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/0', '=FOO(', '=MEDIAN(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('return error when no arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('coerces only explicit arguments, ignores provided via reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="12"', '="11"', '="13"', '=MEDIAN(A1:C1)'], - ['=MEDIAN(TRUE())'], - ['=MEDIAN(1,2,3,B3:C3)'], - ]) - - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.OneValue)) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('ignores nonnumeric values as long as theres at least one numeric value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(TRUE(), "foobar", 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('coerces given string arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN("12", "11", "13")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(12) - }) - - it('empty args as 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIAN(1,2,3,,)'], - ['=MEDIAN(,)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/function-mid.spec.ts b/test/unit/interpreter/function-mid.spec.ts deleted file mode 100644 index 8eeec4e360..0000000000 --- a/test/unit/interpreter/function-mid.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MID', () => { - it('should take three arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID()'], - ['=MID("foo", "bar")'], - ['=MID("foo", "bar", "baz", "qux")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return substring', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID("foo", 1, 2)'], - ['=MID("bar", 2, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('fo') - expect(engine.getCellValue(adr('A2'))).toEqual('ar') - }) - - it('should return empty string if start is greater than text length', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID("", 2, 1)'], - ['=MID("foo", 5, 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('') - }) - - it('should return chars up to string length if end start + number of chars exceeds string length', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID("foo", 2, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('oo') - }) - - it('should return #VALUE! if start num is less than 1', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID("foo", 0, 1)'], - ['=MID("foo", -1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('should return #VALUE! if number of chars is negative', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID("foo", 1, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NegativeLength)) - }) - - it('should coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID(TRUE(), 2, 2)'], - ['=MID(0, 1, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('RU') - expect(engine.getCellValue(adr('A2'))).toEqual('0') - }) - - it('should return error for range', () => { - const engine = HyperFormula.buildFromArray([ - ['=MID(B2:B3, 1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-min.spec.ts b/test/unit/interpreter/function-min.spec.ts deleted file mode 100644 index 99a6b503c3..0000000000 --- a/test/unit/interpreter/function-min.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('MIN', () => { - it('MIN with empty args', () => { - const engine = HyperFormula.buildFromArray([['=MIN()']]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('MIN with args', () => { - const engine = HyperFormula.buildFromArray([['=MIN(1, B1)', '3.14']]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('MIN with range', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=MIN(A1:A3)']]) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('MIN with mixed arguments', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=MIN(4,A1:A3)']]) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('MIN of strings and number', () => { - const engine = HyperFormula.buildFromArray([['foo'], ['bar'], ['5'], ['=MIN(A1:A3)']]) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('doesnt do coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['foo'], - ['=TRUE()'], - ['=CONCATENATE("1","0")'], - ['=MIN(A1:A5)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual(1) - }) - - it('MIN of empty value', () => { - const engine = HyperFormula.buildFromArray([['', '=MIN(A1)']]) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('MIN of empty value and some negative number', () => { - const engine = HyperFormula.buildFromArray([['', '1', '=MIN(A1,B1)']]) - expect(engine.getCellValue(adr('C1'))).toEqual(1) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=MIN(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(7) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=MIN(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-mina.spec.ts b/test/unit/interpreter/function-mina.spec.ts deleted file mode 100644 index 48c8a84a6a..0000000000 --- a/test/unit/interpreter/function-mina.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('MINA', () => { - it('MINA with empty args', () => { - const engine = HyperFormula.buildFromArray([['=MINA()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('MINA with args', () => { - const engine = HyperFormula.buildFromArray([['=MINA(1, B1)', '3.14']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('MINA with range', () => { - const engine = HyperFormula.buildFromArray([['1'], ['3'], ['2'], ['=MINA(A1:A3)']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('does only boolean coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['="42"', '=MINA(A1)'], - ['=TRUE()', '=MINA(A2)'], - ['=FALSE()', '=MINA(A3)'], - ['="TRUE"', '=MINA(A4)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('B2'))).toEqual(1) - expect(engine.getCellValue(adr('B3'))).toEqual(0) - expect(engine.getCellValue(adr('B4'))).toEqual(0) - }) - - it('MINA of empty value', () => { - const engine = HyperFormula.buildFromArray([['', '=MINA(A1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('MINA of empty value and some positive number', () => { - const engine = HyperFormula.buildFromArray([ - ['', '1', '=MINA(A1,B1)'], - [null, '1', '=MINA(A2,B2)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(0) - expect(engine.getCellValue(adr('C2'))).toEqual(1) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=MINA(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(7) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=MINA(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-minifs.spec.ts b/test/unit/interpreter/function-minifs.spec.ts deleted file mode 100644 index 1beacbfa42..0000000000 --- a/test/unit/interpreter/function-minifs.spec.ts +++ /dev/null @@ -1,259 +0,0 @@ -import {HyperFormula, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, expectArrayWithSameContent} from '../testUtils' -import {DateTimeHelper} from '../../../src/DateTimeHelper' -import {Config} from '../../../src/Config' - -describe('Function MINIFS - argument validations and combinations', () => { - it('requires odd number of arguments, but at least 3', () => { - const engine = HyperFormula.buildFromArray([['=MINIFS(C1, ">0")'], ['=MINIFS(C1, ">0", B1, B1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('error when criterion unparsable', () => { - const engine = HyperFormula.buildFromArray([ - ['=MINIFS(B1:B2, C1:C2, "> { - const engine = HyperFormula.buildFromArray([ - ['=MINIFS(B1:C1, B2:D2, ">0")'], - ['=MINIFS(B1, B2:D2, ">0")'], - ['=MINIFS(B1:D1, B2, ">0")'], - ['=MINIFS(B1:D1, B2:D2, ">0", B2:E2, ">0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('error when different height dimension of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MINIFS(B1:B2, C1:C3, ">0")'], - ['=MINIFS(B1, C1:C2, ">0")'], - ['=MINIFS(B1:B2, C1, ">0")'], - ['=MINIFS(B1:B2, C1:C2, ">0", C1:C3, ">0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('scalars are treated like singular arrays', () => { - const engine = HyperFormula.buildFromArray([['=MINIFS(42, 10, ">1")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('should return 0 as min from an empty range', () => { - const engine = HyperFormula.buildFromArray([['=MINIFS(42, -1, ">1")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=MINIFS(4/0, 42, ">1")'], - ['=MINIFS(0, 4/0, ">1")'], - ['=MINIFS(0, 42, 4/0)'], - ['=MINIFS(0, 4/0, FOOBAR())'], - ['=MINIFS(4/0, FOOBAR(), ">1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works when arguments are just references', () => { - const engine = HyperFormula.buildFromArray([['2', '3'], ['=MINIFS(B1, A1, ">1")']]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('works with numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['2', 'a'], - ['3', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('works with percents', () => { - const engine = HyperFormula.buildFromArray([ - ['2%', 'a'], - ['3%', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(.02) - }) - - it('works with currencies', () => { - const engine = HyperFormula.buildFromArray([ - ['$2', 'a'], - ['$3', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('works with dates', () => { - const dateHelper = new DateTimeHelper(new Config()) - - const engine = HyperFormula.buildFromArray([ - ['20/01/2020', 'a'], - ['30/01/2020', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(dateHelper.numberToSimpleDate(engine.getCellValue(adr('A3')) as number)).toEqual({ day: 20, month: 1, year: 2020 }) - }) - - it('strings are ignored', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['abc', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('empty cells are ignored', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('booleans are ignored', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['=TRUE()', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('min of empty cells is zero', () => { - const engine = HyperFormula.buildFromArray([ - ['', 'a'], - ['', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('min of strings is zero', () => { - const engine = HyperFormula.buildFromArray([ - ['abc', 'a'], - ['cba', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('min of booleans is zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', 'a'], - ['=FALSE()', 'a'], - ['=MINIFS(A1:A2, B1:B2, "a")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('works with range values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '3', '5'], - ['1', '1', '7', '9'], - ['=MINIFS(MMULT(C1:D2, C1:D2), MMULT(A1:B2, A1:B2), "=2")'], - ['=MINIFS(MMULT(C1:D2, C1:D2), A1:B2, "=1")'], - ['=MINIFS(C1:D2, MMULT(A1:B2, A1:B2), "=2")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(44) - expect(engine.getCellValue(adr('A4'))).toEqual(44) - expect(engine.getCellValue(adr('A5'))).toEqual(3) - }) - - it('works for mixed reference/range arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=MINIFS(B1, A1:A1, ">1")'], - ['4', '5'], - ['=MINIFS(B3:B3, A3, ">1")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('works when criterion arg is an inline array', () => { - const engine = HyperFormula.buildFromArray([[2, 'a'], [3, 'b'], ['=MINIFS(A1:A2, B1:B2, {"a", "b"})']], { - useArrayArithmetic: true, - }) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('B3'))).toEqual(3) - }) -}) - -describe('Function MINIFS - calcultions on more than one criteria', () => { - it('works for more than one criterion/range pair', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '100', '3'], - ['1', '101', '5'], - ['2', '102', '7'], - ['=MINIFS(C1:C3, A1:A3, ">=1", B1:B3, "<102")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) -}) - -describe('Function MINIFS - cache recalculation after cruds', () => { - it('recalculates MINIFS if changes in the first range', () => { - const sheet = [['10', '10'], ['5', '6'], ['7', '8'], ['=MINIFS(A1:B1, A2:B2, ">=5", A3:B3, ">=7")']] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), [['1', '3']]) - const newValues = changes.map(c => c.newValue) - - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expectArrayWithSameContent(newValues, [1, 3, 1]) - }) - - it('recalculates MINIFS if changes in one of the tested range', () => { - const sheet = [['10', '20'], ['5', '6'], ['7', '8'], ['=MINIFS(A1:B1, A2:B2, ">=5", A3:B3, ">=7")']] - const engine = HyperFormula.buildFromArray(sheet) - expect(engine.getCellValue(adr('A4'))).toEqual(10) - - engine.setCellContents(adr('A3'), [['1', '7']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(20) - }) -}) diff --git a/test/unit/interpreter/function-minute.spec.ts b/test/unit/interpreter/function-minute.spec.ts deleted file mode 100644 index 454fcb92af..0000000000 --- a/test/unit/interpreter/function-minute.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MINUTE', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=MINUTE("foo")', '=MINUTE("12/30/2018")', '=MINUTE(1, 2)', '=MINUTE()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([['=MINUTE(0.5123456)', '=MINUTE(0)', '=MINUTE(0.999999)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(17) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=MINUTE("14:42:59")', '=MINUTE("01/01/1900 03:01:02am")', '=MINUTE("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - - it('use datenumber coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=MINUTE(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=MINUTE(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-mirr.spec.ts b/test/unit/interpreter/function-mirr.spec.ts deleted file mode 100644 index a374bf3183..0000000000 --- a/test/unit/interpreter/function-mirr.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MIRR', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MIRR(1, 1)'], - ['=MIRR(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=MIRR(B1:F1, 0.3, -0.1)', 1, 2, -3, -5, 8], - ['=MIRR(B2:C2, 1, 1)', -1, 1], - ['=MIRR(B3:E3, 0.2, 0.1)', -1, 0, -1, 1], - ['=MIRR(B4:D4, 0.2, 0.1)', -1, -1, 1], - ['=MIRR(B5:D5, -2, 1)', 3, 4, -3] - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.257018945686308, 6) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.161201673643132, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(-0.261451054124004, 6) // different value without 0 - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(1.58198889747161, 6) - }) - - it('should return #DIV/0! if "contains at least one positive and one negative value" condition is not met', () => { - const engine = HyperFormula.buildFromArray([ - ['=MIRR(B1:E1,0.2,0.1)', -1, 0, -1, -1], - ['=MIRR(B2:E2,0.2,0.1)', 1, 0, 1, 1], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return #DIV/0! if any rate is -1', () => { - const engine = HyperFormula.buildFromArray([ - ['=MIRR(B1:E1,-1,0.1)', -1, 1, -1, -1], - ['=MIRR(B2:E2,0.2,-1)', 1, -1, 1, 1], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should ignore text, boolean and empty values', () => { - const engine = HyperFormula.buildFromArray([ - ['=MIRR(B1:H1,0.2,0.1)', -1, 0, 'abcd', true, null, -1, 1], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-0.161201673643132, 6) - }) - - it('should return contained error if one exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=MIRR(B1:E1,-1,0.1)', -1, 1, '=CONCATENATE(FOO)', -1], - ['=MIRR(B2:E2,0.2,-1)', 1, '=FIND("h","bar")', 1, 1], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('FOO'))) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - }) -}) diff --git a/test/unit/interpreter/function-modulo.spec.ts b/test/unit/interpreter/function-modulo.spec.ts deleted file mode 100644 index 1de7766a5a..0000000000 --- a/test/unit/interpreter/function-modulo.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MOD', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MOD(101)'], - ['=MOD(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=MOD(1, "foo")'], - ['=MOD("bar", 4)'], - ['=MOD("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return error when dividing by 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=MOD(42, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=MOD(5, 2)'], - ['=MOD(36, 6)'], - ['=MOD(10.5, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(1.5) - }) -}) diff --git a/test/unit/interpreter/function-month.spec.ts b/test/unit/interpreter/function-month.spec.ts deleted file mode 100644 index a070c83bde..0000000000 --- a/test/unit/interpreter/function-month.spec.ts +++ /dev/null @@ -1,229 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MONTH', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=MONTH("foo")', '=MONTH("12/30/2018")', '=MONTH(1, 2)', '=MONTH()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([['=MONTH(0)', '=MONTH(2)', '=MONTH(43465)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(12) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=MONTH("31/12/1899")', '=MONTH("01/01/1900")', '=MONTH("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(12) - }) - - it('use datenumber coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(TRUE())'], - ['=MONTH(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - expect(engine.getCellValue(adr('A2'))).toEqual(12) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('test for days in month, start of month', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(DATE(2021,1,1))'], - ['=MONTH(DATE(2021,2,1))'], - ['=MONTH(DATE(2021,3,1))'], - ['=MONTH(DATE(2021,4,1))'], - ['=MONTH(DATE(2021,5,1))'], - ['=MONTH(DATE(2021,6,1))'], - ['=MONTH(DATE(2021,7,1))'], - ['=MONTH(DATE(2021,8,1))'], - ['=MONTH(DATE(2021,9,1))'], - ['=MONTH(DATE(2021,10,1))'], - ['=MONTH(DATE(2021,11,1))'], - ['=MONTH(DATE(2021,12,1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - expect(engine.getCellValue(adr('A6'))).toEqual(6) - expect(engine.getCellValue(adr('A7'))).toEqual(7) - expect(engine.getCellValue(adr('A8'))).toEqual(8) - expect(engine.getCellValue(adr('A9'))).toEqual(9) - expect(engine.getCellValue(adr('A10'))).toEqual(10) - expect(engine.getCellValue(adr('A11'))).toEqual(11) - expect(engine.getCellValue(adr('A12'))).toEqual(12) - }) - - it('test for days in month, end of month', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(DATE(2021,1,31))'], - ['=MONTH(DATE(2021,2,28))'], - ['=MONTH(DATE(2021,3,31))'], - ['=MONTH(DATE(2021,4,30))'], - ['=MONTH(DATE(2021,5,31))'], - ['=MONTH(DATE(2021,6,30))'], - ['=MONTH(DATE(2021,7,31))'], - ['=MONTH(DATE(2021,8,31))'], - ['=MONTH(DATE(2021,9,30))'], - ['=MONTH(DATE(2021,10,31))'], - ['=MONTH(DATE(2021,11,30))'], - ['=MONTH(DATE(2021,12,31))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - expect(engine.getCellValue(adr('A6'))).toEqual(6) - expect(engine.getCellValue(adr('A7'))).toEqual(7) - expect(engine.getCellValue(adr('A8'))).toEqual(8) - expect(engine.getCellValue(adr('A9'))).toEqual(9) - expect(engine.getCellValue(adr('A10'))).toEqual(10) - expect(engine.getCellValue(adr('A11'))).toEqual(11) - expect(engine.getCellValue(adr('A12'))).toEqual(12) - }) - - it('test for days in month, end of month+1', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(DATE(2021,1,31)+1)'], - ['=MONTH(DATE(2021,2,28)+1)'], - ['=MONTH(DATE(2021,3,31)+1)'], - ['=MONTH(DATE(2021,4,30)+1)'], - ['=MONTH(DATE(2021,5,31)+1)'], - ['=MONTH(DATE(2021,6,30)+1)'], - ['=MONTH(DATE(2021,7,31)+1)'], - ['=MONTH(DATE(2021,8,31)+1)'], - ['=MONTH(DATE(2021,9,30)+1)'], - ['=MONTH(DATE(2021,10,31)+1)'], - ['=MONTH(DATE(2021,11,30)+1)'], - ['=MONTH(DATE(2021,12,31)+1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - expect(engine.getCellValue(adr('A5'))).toEqual(6) - expect(engine.getCellValue(adr('A6'))).toEqual(7) - expect(engine.getCellValue(adr('A7'))).toEqual(8) - expect(engine.getCellValue(adr('A8'))).toEqual(9) - expect(engine.getCellValue(adr('A9'))).toEqual(10) - expect(engine.getCellValue(adr('A10'))).toEqual(11) - expect(engine.getCellValue(adr('A11'))).toEqual(12) - expect(engine.getCellValue(adr('A12'))).toEqual(1) - }) - - it('test for days in month, start of month, leap year', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(DATE(2020,1,1))'], - ['=MONTH(DATE(2020,2,1))'], - ['=MONTH(DATE(2020,3,1))'], - ['=MONTH(DATE(2020,4,1))'], - ['=MONTH(DATE(2020,5,1))'], - ['=MONTH(DATE(2020,6,1))'], - ['=MONTH(DATE(2020,7,1))'], - ['=MONTH(DATE(2020,8,1))'], - ['=MONTH(DATE(2020,9,1))'], - ['=MONTH(DATE(2020,10,1))'], - ['=MONTH(DATE(2020,11,1))'], - ['=MONTH(DATE(2020,12,1))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - expect(engine.getCellValue(adr('A6'))).toEqual(6) - expect(engine.getCellValue(adr('A7'))).toEqual(7) - expect(engine.getCellValue(adr('A8'))).toEqual(8) - expect(engine.getCellValue(adr('A9'))).toEqual(9) - expect(engine.getCellValue(adr('A10'))).toEqual(10) - expect(engine.getCellValue(adr('A11'))).toEqual(11) - expect(engine.getCellValue(adr('A12'))).toEqual(12) - }) - - it('test for days in month, end of month, leap year', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(DATE(2020,1,31))'], - ['=MONTH(DATE(2020,2,29))'], - ['=MONTH(DATE(2020,3,31))'], - ['=MONTH(DATE(2020,4,30))'], - ['=MONTH(DATE(2020,5,31))'], - ['=MONTH(DATE(2020,6,30))'], - ['=MONTH(DATE(2020,7,31))'], - ['=MONTH(DATE(2020,8,31))'], - ['=MONTH(DATE(2020,9,30))'], - ['=MONTH(DATE(2020,10,31))'], - ['=MONTH(DATE(2020,11,30))'], - ['=MONTH(DATE(2020,12,31))'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - expect(engine.getCellValue(adr('A6'))).toEqual(6) - expect(engine.getCellValue(adr('A7'))).toEqual(7) - expect(engine.getCellValue(adr('A8'))).toEqual(8) - expect(engine.getCellValue(adr('A9'))).toEqual(9) - expect(engine.getCellValue(adr('A10'))).toEqual(10) - expect(engine.getCellValue(adr('A11'))).toEqual(11) - expect(engine.getCellValue(adr('A12'))).toEqual(12) - }) - - it('test for days in month, end of month+1, leap year', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(DATE(2020,1,31)+1)'], - ['=MONTH(DATE(2020,2,29)+1)'], - ['=MONTH(DATE(2020,3,31)+1)'], - ['=MONTH(DATE(2020,4,30)+1)'], - ['=MONTH(DATE(2020,5,31)+1)'], - ['=MONTH(DATE(2020,6,30)+1)'], - ['=MONTH(DATE(2020,7,31)+1)'], - ['=MONTH(DATE(2020,8,31)+1)'], - ['=MONTH(DATE(2020,9,30)+1)'], - ['=MONTH(DATE(2020,10,31)+1)'], - ['=MONTH(DATE(2020,11,30)+1)'], - ['=MONTH(DATE(2020,12,31)+1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - expect(engine.getCellValue(adr('A5'))).toEqual(6) - expect(engine.getCellValue(adr('A6'))).toEqual(7) - expect(engine.getCellValue(adr('A7'))).toEqual(8) - expect(engine.getCellValue(adr('A8'))).toEqual(9) - expect(engine.getCellValue(adr('A9'))).toEqual(10) - expect(engine.getCellValue(adr('A10'))).toEqual(11) - expect(engine.getCellValue(adr('A11'))).toEqual(12) - expect(engine.getCellValue(adr('A12'))).toEqual(1) - }) -}) diff --git a/test/unit/interpreter/function-mround.spec.ts b/test/unit/interpreter/function-mround.spec.ts deleted file mode 100644 index 19ef6f5f61..0000000000 --- a/test/unit/interpreter/function-mround.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MROUND', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MROUND(101)'], - ['=MROUND(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=MROUND(1, "foo")'], - ['=MROUND("bar", 4)'], - ['=MROUND("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return 0 when dividing by 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=MROUND(42, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('should return error for args of different signs', () => { - const engine = HyperFormula.buildFromArray([ - ['=MROUND(42, -1)'], - ['=MROUND(-42, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.DistinctSigns)) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.DistinctSigns)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=MROUND(5, 2)'], - ['=MROUND(36, 6.5)'], - ['=MROUND(10.5, 3)'], - ['=MROUND(-5, -2)'], - ['=MROUND(-36, -6.5)'], - ['=MROUND(-10.5, -3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(39) - expect(engine.getCellValue(adr('A3'))).toEqual(12) - expect(engine.getCellValue(adr('A4'))).toEqual(-6) - expect(engine.getCellValue(adr('A5'))).toEqual(-39) - expect(engine.getCellValue(adr('A6'))).toEqual(-12) - }) - - /** - * Tests below are results of how floating point arithmetic works. - * This behavior is undefined, and this is test for consistency between platforms. - * If this test starts throwing errors, it should be disabled. - */ - it('known limitations', () => { - const engine = HyperFormula.buildFromArray([ - ['=MROUND(6.05, 0.1)'], - ['=MROUND(7.05, 0.1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(7.1) - }) -}) diff --git a/test/unit/interpreter/function-multinomial.spec.ts b/test/unit/interpreter/function-multinomial.spec.ts deleted file mode 100644 index b2192445bf..0000000000 --- a/test/unit/interpreter/function-multinomial.spec.ts +++ /dev/null @@ -1,93 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function MULTINOMIAL', () => { - it('checks required number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('computes correct answer for two args', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL(6,8)', '=MULTINOMIAL(0,0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3003) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('computes correct answer for more than two args', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL(2,3,5,7)', '=MULTINOMIAL(10,11,12,13,14)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(49008960) - expect(engine.getCellValue(adr('B1')) as number / 2.20917676017678e+38).toBeCloseTo(1, 6) - }) - - it('accepts single arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL(1000)', '=MULTINOMIAL(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('coerces to number', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL("2",4)'], - ['=MULTINOMIAL(B2:C2)', '\'2', 4], - ['=MULTINOMIAL(TRUE(),4)'], - ['=MULTINOMIAL(B4:C4)', true, 4], - ['=MULTINOMIAL(,4)'], - ['=MULTINOMIAL(B6:C6)', null, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(15) - expect(engine.getCellValue(adr('A2'))).toBe(15) - expect(engine.getCellValue(adr('A3'))).toBe(5) - expect(engine.getCellValue(adr('A4'))).toBe(5) - expect(engine.getCellValue(adr('A5'))).toBe(1) - expect(engine.getCellValue(adr('A6'))).toBe(1) - }) - - it('throws error for non-coercible values', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL(B1:C1)', 'abcd', 4], - ['=MULTINOMIAL("abcd",4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL(-1,5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('truncates numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL(B1:C1)', 5.5, 10.9], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3003) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=MULTINOMIAL(NA(),4)'], - ['=MULTINOMIAL(B2:C2)', '=NA()', 4], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-na.spec.ts b/test/unit/interpreter/function-na.spec.ts deleted file mode 100644 index 32940a8c2c..0000000000 --- a/test/unit/interpreter/function-na.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {adr, detailedError} from '../testUtils' - -describe('Function NA', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=NA(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-negbinom.dist.spec.ts b/test/unit/interpreter/function-negbinom.dist.spec.ts deleted file mode 100644 index 8b42069684..0000000000 --- a/test/unit/interpreter/function-negbinom.dist.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NEGBINOM.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NEGBINOM.DIST(1, 2, 3)'], - ['=NEGBINOM.DIST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=NEGBINOM.DIST("foo", 2, 1, TRUE())'], - ['=NEGBINOM.DIST(1, "baz", 1, TRUE())'], - ['=NEGBINOM.DIST(1, 2, "baz", TRUE())'], - ['=NEGBINOM.DIST(1, 2, 1, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=NEGBINOM.DIST(10, 20, 0.5, TRUE())'], - ['=NEGBINOM.DIST(2, 3, 0.1, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0493685733526945, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.00856, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=NEGBINOM.DIST(10, 20, 0.5, FALSE())'], - ['=NEGBINOM.DIST(2, 3, 0.1, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0186544004827738, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.00486, 6) - }) - - it('truncates first and second arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=NEGBINOM.DIST(10.9, 20, 0.5, FALSE())'], - ['=NEGBINOM.DIST(2, 3.9, 0.1, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0186544004827738, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.00486, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=NEGBINOM.DIST(0, 1, 0.5, FALSE())'], - ['=NEGBINOM.DIST(-0.001, 1, 0.5, FALSE())'], - ['=NEGBINOM.DIST(0, 0.999, 0.5, FALSE())'], - ['=NEGBINOM.DIST(0, 1, 0, FALSE())'], - ['=NEGBINOM.DIST(0, 1, -0.01, FALSE())'], - ['=NEGBINOM.DIST(0, 1, 1, FALSE())'], - ['=NEGBINOM.DIST(0, 1, 1.01, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - //product #2 returns error - expect(engine.getCellValue(adr('A4'))).toEqual(0) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - //product #2 returns error - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-networkdays.intl.spec.ts b/test/unit/interpreter/function-networkdays.intl.spec.ts deleted file mode 100644 index 87fd430f3a..0000000000 --- a/test/unit/interpreter/function-networkdays.intl.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NETWORKDAYS.INTL', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NETWORKDAYS.INTL(1)', '=NETWORKDAYS.INTL(1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should check for types or value of third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=NETWORKDAYS.INTL(0, 1, TRUE())'], - ['=NETWORKDAYS.INTL(0, 1, "1")'], - ['=NETWORKDAYS.INTL(0, 1, "1010102")'], - ['=NETWORKDAYS.INTL(0, 1, -1)'], - ['=NETWORKDAYS.INTL(0, 1, "1111111")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WeekendString)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WeekendString)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WeekendString)) - }) - - it('works correctly for first two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NETWORKDAYS.INTL(0, 1)'], - ['=NETWORKDAYS.INTL(0, 6)'], - ['=NETWORKDAYS.INTL(0, 6.9)'], - ['=NETWORKDAYS.INTL(6.9,0.1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - expect(engine.getCellValue(adr('A4'))).toEqual(-5) - }) - - it('today', () => { - const engine = HyperFormula.buildFromArray([ - ['=NETWORKDAYS.INTL("29/09/2020", "29/09/2020")'], - ['=NETWORKDAYS.INTL("29/09/2020", "29/09/2020", 3)'], - ['=NETWORKDAYS.INTL("29/09/2020", "29/09/2020", 4)'], - ['=NETWORKDAYS.INTL("29/09/2020", "29/09/2020", 13)'], - ['=NETWORKDAYS.INTL("29/09/2020", "29/09/2020", "1011111")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - expect(engine.getCellValue(adr('A4'))).toEqual(0) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - }) - - it('this year', () => { - const engine = HyperFormula.buildFromArray([ - ['29/09/2020', '=A1+0.1', '31/12/2019', '01/01/2021', '27/09/2020'], - ['=NETWORKDAYS.INTL("01/01/2020", "31/12/2020", 1)'], - ['=NETWORKDAYS.INTL("01/01/2020", "31/12/2020", 1, A1:A1)'], - ['=NETWORKDAYS.INTL("01/01/2020", "31/12/2020", 1, A1:B1)'], - ['=NETWORKDAYS.INTL("01/01/2020", "31/12/2020", 1, A1:D1)'], - ['=NETWORKDAYS.INTL("01/01/2020", "31/12/2020", 1, A1:E1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(262) - expect(engine.getCellValue(adr('A3'))).toEqual(261) - expect(engine.getCellValue(adr('A4'))).toEqual(261) - expect(engine.getCellValue(adr('A5'))).toEqual(261) - expect(engine.getCellValue(adr('A6'))).toEqual(261) - }) - - it('should output correct values', () => { - const engine = HyperFormula.buildFromArray([ - ['01/01/2020', '=A1+5', '=A1+8', '=A1+9', '=A1+15', '=A1+18', '=A1+19', '=A1+32', '=A1+54', '=A1+55'], - ['=NETWORKDAYS.INTL(A1, A1+100, "0000000", A1:J1)'], - ['=NETWORKDAYS.INTL(A1+7, A1+20, "0000000", A1:J1)'], - ['=NETWORKDAYS.INTL(A1+7, A1+100, "0000000", A1:J1)'], - ['=NETWORKDAYS.INTL(A1+13, A1+50, "0000000", A1:J1)'], - ['=NETWORKDAYS.INTL(A1+50, A1+56, "0000000", A1:J1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(91) - expect(engine.getCellValue(adr('A3'))).toEqual(9) - expect(engine.getCellValue(adr('A4'))).toEqual(86) - expect(engine.getCellValue(adr('A5'))).toEqual(34) - expect(engine.getCellValue(adr('A6'))).toEqual(5) - }) - - it('checks types in last argument', () => { - const engine = HyperFormula.buildFromArray([ - [true, '\'1', null, '=NA()'], - ['=NETWORKDAYS.INTL(1000, 1, 1, A1:A1)'], - ['=NETWORKDAYS.INTL(1000, 1, 1, B1:B1)'], - ['=NETWORKDAYS.INTL(1000, 1, 1, C1:C1)'], - ['=NETWORKDAYS.INTL(1000, 1, 1, A1:D1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A4'))).toEqual(-715) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-networkdays.spec.ts b/test/unit/interpreter/function-networkdays.spec.ts deleted file mode 100644 index b109aff473..0000000000 --- a/test/unit/interpreter/function-networkdays.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NETWORKDAYS', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NETWORKDAYS(1)', '=NETWORKDAYS(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works correctly for first two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NETWORKDAYS(0, 1)'], - ['=NETWORKDAYS(0, 6)'], - ['=NETWORKDAYS(0, 6.9)'], - ['=NETWORKDAYS(6.9,0.1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - expect(engine.getCellValue(adr('A4'))).toEqual(-5) - }) - - it('this year', () => { - const engine = HyperFormula.buildFromArray([ - ['29/09/2020', '=A1+0.1', '31/12/2019', '01/01/2021', '27/09/2020'], - ['=NETWORKDAYS("01/01/2020", "31/12/2020")'], - ['=NETWORKDAYS("01/01/2020", "31/12/2020", A1:A1)'], - ['=NETWORKDAYS("01/01/2020", "31/12/2020", A1:B1)'], - ['=NETWORKDAYS("01/01/2020", "31/12/2020", A1:D1)'], - ['=NETWORKDAYS("01/01/2020", "31/12/2020", A1:E1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(262) - expect(engine.getCellValue(adr('A3'))).toEqual(261) - expect(engine.getCellValue(adr('A4'))).toEqual(261) - expect(engine.getCellValue(adr('A5'))).toEqual(261) - expect(engine.getCellValue(adr('A6'))).toEqual(261) - }) - - it('should output correct values', () => { - const engine = HyperFormula.buildFromArray([ - ['01/01/2020', '=A1+5', '=A1+8', '=A1+9', '=A1+15', '=A1+18', '=A1+19', '=A1+32', '=A1+54', '=A1+55'], - ['=NETWORKDAYS(A1, A1+100, A1:J1)'], - ['=NETWORKDAYS(A1+7, A1+20, A1:J1)'], - ['=NETWORKDAYS(A1+7, A1+100, A1:J1)'], - ['=NETWORKDAYS(A1+13, A1+50, A1:J1)'], - ['=NETWORKDAYS(A1+50, A1+56, A1:J1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(65) - expect(engine.getCellValue(adr('A3'))).toEqual(6) - expect(engine.getCellValue(adr('A4'))).toEqual(62) - expect(engine.getCellValue(adr('A5'))).toEqual(26) - expect(engine.getCellValue(adr('A6'))).toEqual(3) - }) - - it('checks types in last argument', () => { - const engine = HyperFormula.buildFromArray([ - [true, '\'1', null, '=NA()'], - ['=NETWORKDAYS(1000, 1, A1:A1)'], - ['=NETWORKDAYS(1000, 1, B1:B1)'], - ['=NETWORKDAYS(1000, 1, C1:C1)'], - ['=NETWORKDAYS(1000, 1, A1:D1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A4'))).toEqual(-715) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-nominal.spec.ts b/test/unit/interpreter/function-nominal.spec.ts deleted file mode 100644 index 99c9c9ccd1..0000000000 --- a/test/unit/interpreter/function-nominal.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NOMINAL', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NOMINAL(1)', '=NOMINAL(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=NOMINAL(2%, 1)', '=NOMINAL(2%, 2)', '=NOMINAL(2%, 2.9)', '=NOMINAL(2%, 24)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.02, 9) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.0199009876724157, 9) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(0.0199009876724157, 9) - expect(engine.getCellValue(adr('D1'))).toBeCloseTo(0.0198107992112657, 9) - }) -}) diff --git a/test/unit/interpreter/function-norm.dist.spec.ts b/test/unit/interpreter/function-norm.dist.spec.ts deleted file mode 100644 index a40195edd6..0000000000 --- a/test/unit/interpreter/function-norm.dist.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NORM.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.DIST(1, 2, 3)'], - ['=NORM.DIST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.DIST("foo", 2, 3, TRUE())'], - ['=NORM.DIST(1, "baz", 3, TRUE())'], - ['=NORM.DIST(1, 2, "baz", TRUE())'], - ['=NORM.DIST(1, 2, 3, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.DIST(-1, 1, 2, TRUE())'], - ['=NORM.DIST(0.5, 2, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.158655253931457, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.353830233327276, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.DIST(-1, 1, 2, FALSE())'], - ['=NORM.DIST(0.5, 2, 4, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.120985362259572, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0929637734674423, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.DIST(-1, -1, 0.01, FALSE())'], - ['=NORM.DIST(-1, -1, 0, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(39.8942280401433, 6) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-norm.inv.spec.ts b/test/unit/interpreter/function-norm.inv.spec.ts deleted file mode 100644 index 8700b55546..0000000000 --- a/test/unit/interpreter/function-norm.inv.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NORM.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.INV(1, 2)'], - ['=NORM.INV(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.INV("foo", 2, 3)'], - ['=NORM.INV(0.5, "baz", 3)'], - ['=NORM.INV(0.5, 2, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.INV(0.9, 1, 2)'], - ['=NORM.INV(0.5, 2, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(3.5631031310892, 6) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.INV(0.5, -1, 0.01)'], - ['=NORM.INV(0.5, -1, 0)'], - ['=NORM.INV(0.01, -1, 0.01)'], - ['=NORM.INV(0, -1, 0.01)'], - ['=NORM.INV(0.99, -1, 0.01)'], - ['=NORM.INV(1, -1, 0.01)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-1) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-1.02326347874041, 6) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(-0.976736521259592, 6) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-norm.s.dist.spec.ts b/test/unit/interpreter/function-norm.s.dist.spec.ts deleted file mode 100644 index e2ad8a2c4d..0000000000 --- a/test/unit/interpreter/function-norm.s.dist.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NORM.S.DIST', () => { - //in product #1, this function takes 1 argument - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.DIST(2)'], - ['=NORM.S.DIST(1, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - //in product #1, this function takes 1 argument - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.DIST("foo", TRUE())'], - ['=NORM.S.DIST(1, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - //in product #1, this function takes 1 argument - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.DIST(-1, TRUE())'], - ['=NORM.S.DIST(0.5, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.158655253931457, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.691462461274013, 6) - }) - - //in product #1, this function takes 1 argument - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.DIST(-1, FALSE())'], - ['=NORM.S.DIST(0.5, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.241970724519143, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.3520653267643, 6) - }) -}) diff --git a/test/unit/interpreter/function-norm.s.inv.spec.ts b/test/unit/interpreter/function-norm.s.inv.spec.ts deleted file mode 100644 index 3ca2d7a089..0000000000 --- a/test/unit/interpreter/function-norm.s.inv.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NORM.S.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.INV()'], - ['=NORM.S.INV(3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.INV("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.INV(0.9)'], - ['=NORM.S.INV(0.5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.2815515655446, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=NORM.S.INV(0.01)'], - ['=NORM.S.INV(0)'], - ['=NORM.S.INV(0.99)'], - ['=NORM.S.INV(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-2.32634787404084, 6) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(2.32634787404084, 6) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-not.spec.ts b/test/unit/interpreter/function-not.spec.ts deleted file mode 100644 index 1e95699c8c..0000000000 --- a/test/unit/interpreter/function-not.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NOT', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NOT()', '=NOT(TRUE(), TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=NOT(TRUE())', '=NOT(FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=NOT("FALSE")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=NOT(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-now.spec.ts b/test/unit/interpreter/function-now.spec.ts deleted file mode 100644 index e35124706c..0000000000 --- a/test/unit/interpreter/function-now.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - function NOW', () => { - let originalNow: () => number - - beforeEach(() => { - originalNow = Date.now - let cnt = 20 - Date.now = () => { - cnt += 1 - return Date.parse(`1985-08-16T03:45:${cnt}`) - } - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=NOW()'], - ]) - const t1 = engine.getCellValue(adr('A1')) as number - expect(t1).toBeCloseTo(31275.1565856481) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - engine.setCellContents(adr('A2'), null) - const delta = engine.getCellValue(adr('A1')) as number - t1 - expect(delta * 24 * 60 * 60).toBeGreaterThanOrEqual(1) //internals of the engine are also using Date.now(), so the value should be actually 4 or even more - }) - - it('works #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEAR(NOW())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1985) - }) - - it('works #3', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(NOW())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(8) - }) - - it('works #4', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(NOW())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(16) - }) - - it('works #5', () => { - const engine = HyperFormula.buildFromArray([ - ['=HOUR(NOW())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works #6', () => { - const engine = HyperFormula.buildFromArray([ - ['=MINUTE(NOW())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(45) - }) - - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NOW(42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - afterEach(() => { - Date.now = originalNow - }) -}) diff --git a/test/unit/interpreter/function-nper.spec.ts b/test/unit/interpreter/function-nper.spec.ts deleted file mode 100644 index 877a2c8dda..0000000000 --- a/test/unit/interpreter/function-nper.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NPER', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPER(1,1)', '=NPER(1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPER(1%, 1, 100, 1)', '=NPER(1%, 1, 100, 1, 1)', '=NPER(1%, 1, 100, 1, 2)'], - ['=NPER(100%, -50, 100, 0, 1)', '=NPER(100%, -50, 100, -100, 1)', '=NPER(-100%, 1, 100, 1, 1)', '=NPER(-200%, 1, 100, 1, 1)'], - ['=NPER(-20%, -50, 100, 300, 1)', ], - ['=NPER(0%, -50, 100, 300, 1)', ], - ['=NPER(0%, 0, 100, 100, 1)', '=NPER(0%, 0, 100, -100, 1)'], - ['=NPER(1%, 0, 100, 100, 1)', '=NPER(1%, 0, 100, -50, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-70.67076731) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-70.16196068) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(-70.16196068) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('D2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A4'))).toEqual(8) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('B6'))).toBeCloseTo(-69.66071689) - }) -}) diff --git a/test/unit/interpreter/function-npv.spec.ts b/test/unit/interpreter/function-npv.spec.ts deleted file mode 100644 index ec9e55dd7a..0000000000 --- a/test/unit/interpreter/function-npv.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function NPV', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPV(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should ignore logical and text values', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPV(1, B1:C1)', 1, 'abcd'], - ['=NPV(1, B2:C2)', true, 1], - ['=NPV(-1, 0)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('A2'))).toEqual(0.5) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - }) - - it('should be compatible with product #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPV(1, TRUE(), 1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.75) //product #1 returns 0.5 - }) - - it('order of arguments matters', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPV(1, A2:B3)'], - [1, 2], - [3, 4], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1.625) - }) - - it('should return correct error value', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPV(1, NA())'], - ['=NPV(1, 1, "abcd")'], - ['=NPV(-1,1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - /** - * Inconsistency with products #1 and #2. - */ - it('cell reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=NPV(1,B1)', true] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) //Both products #1 and #2 return 0 here. - }) -}) diff --git a/test/unit/interpreter/function-oct2bin.spec.ts b/test/unit/interpreter/function-oct2bin.spec.ts deleted file mode 100644 index 59c2720655..0000000000 --- a/test/unit/interpreter/function-oct2bin.spec.ts +++ /dev/null @@ -1,131 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function OCT2BIN', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-oct arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN("foo")'], - ['=OCT2BIN(418)'], - ['=OCT2BIN(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(1)'], - ['=OCT2BIN(10)'], - ['=OCT2BIN(71)'], - ['=OCT2BIN(777)'], - ['=OCT2BIN(7777777000)'], - ['=OCT2BIN(7777777042)'], - ['=OCT2BIN(7777777777)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('1000') - expect(engine.getCellValue(adr('A3'))).toEqual('111001') - expect(engine.getCellValue(adr('A4'))).toEqual('111111111') - expect(engine.getCellValue(adr('A5'))).toEqual('1000000000') - expect(engine.getCellValue(adr('A6'))).toEqual('1000100010') - expect(engine.getCellValue(adr('A7'))).toEqual('1111111111') - }) - - it('should work for strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN("456")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('100101110') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="123"'], - ['=OCT2BIN(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('1010011') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(11)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should work only for 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(10101010101010)'], - ['=OCT2BIN(7777777042)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A2'))).toEqual('1000100010') - }) - - it('result cannot be longer than 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(1000)'], - ['=OCT2BIN(7777776777)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseSmall)) - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(12, 8)'], - ['=OCT2BIN(3, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('00001010') - expect(engine.getCellValue(adr('A2'))).toEqual('0011') - }) - - it('second argument should not affect negative results', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(7777777042, 1)'], - ['=OCT2BIN(7777777042, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1000100010') - expect(engine.getCellValue(adr('A2'))).toEqual('1000100010') - }) - - it('should fail if the result is longer than the desired length', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(12123, 2)'], - ['=OCT2BIN(34141, "3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLarge)) - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2BIN(2, 0)'], - ['=OCT2BIN(2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-oct2dec.spec.ts b/test/unit/interpreter/function-oct2dec.spec.ts deleted file mode 100644 index fb3a69ba40..0000000000 --- a/test/unit/interpreter/function-oct2dec.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function OCT2DEC', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2DEC("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-oct arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2DEC("foo")'], - ['=OCT2DEC(418)'], - ['=OCT2DEC(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2DEC(1)'], - ['=OCT2DEC(10)'], - ['=OCT2DEC(71)'], - ['=OCT2DEC(12345)'], - ['=OCT2DEC(4242565)'], - ['=OCT2DEC(1234567654)'], - ['=OCT2DEC(7777777000)'], - ['=OCT2DEC(7777777042)'], - ['=OCT2DEC(7777777777)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(8) - expect(engine.getCellValue(adr('A3'))).toEqual(57) - expect(engine.getCellValue(adr('A4'))).toEqual(5349) - expect(engine.getCellValue(adr('A5'))).toEqual(1131893) - expect(engine.getCellValue(adr('A6'))).toEqual(175304620) - expect(engine.getCellValue(adr('A7'))).toEqual(-512) - expect(engine.getCellValue(adr('A8'))).toEqual(-478) - expect(engine.getCellValue(adr('A9'))).toEqual(-1) - }) - - it('should work for strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2DEC("456")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(302) - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="123"'], - ['=OCT2DEC(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(83) - }) - - it('should return a number', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2DEC(11)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.NUMBER) - }) - - it('should work only for 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2DEC(10107040205)'], - ['=OCT2DEC(7777777042)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A2'))).toEqual(-478) - }) -}) diff --git a/test/unit/interpreter/function-oct2hex.spec.ts b/test/unit/interpreter/function-oct2hex.spec.ts deleted file mode 100644 index 26c193d90c..0000000000 --- a/test/unit/interpreter/function-oct2hex.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('function OCT2HEX', () => { - it('should return error when wrong number of argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX("foo", 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for non-oct arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX("foo")'], - ['=OCT2HEX(418)'], - ['=OCT2HEX(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX(1)'], - ['=OCT2HEX(10)'], - ['=OCT2HEX(71)'], - ['=OCT2HEX(12345)'], - ['=OCT2HEX(4242565)'], - ['=OCT2HEX(1234567654)'], - ['=OCT2HEX(7777777000)'], - ['=OCT2HEX(7777777042)'], - ['=OCT2HEX(7777777777)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('8') - expect(engine.getCellValue(adr('A3'))).toEqual('39') - expect(engine.getCellValue(adr('A4'))).toEqual('14E5') - expect(engine.getCellValue(adr('A5'))).toEqual('114575') - expect(engine.getCellValue(adr('A6'))).toEqual('A72EFAC') - expect(engine.getCellValue(adr('A7'))).toEqual('FFFFFFFE00') - expect(engine.getCellValue(adr('A8'))).toEqual('FFFFFFFE22') - expect(engine.getCellValue(adr('A9'))).toEqual('FFFFFFFFFF') - }) - - it('should work for strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX("456")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('12E') - }) - - it('should work for reference', () => { - const engine = HyperFormula.buildFromArray([ - ['="123"'], - ['=OCT2HEX(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('53') - }) - - it('should return string value', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX(11)'], - ]) - - expect(engine.getCellValueType(adr('A1'))).toBe(CellValueType.STRING) - }) - - it('should work only for 10 digits', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX(31030220101)'], - ['=OCT2HEX(7777777042)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NotOctal)) - expect(engine.getCellValue(adr('A2'))).toEqual('FFFFFFFE22') - }) - - it('should respect second argument and fill with zeros for positive arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX(12, 8)'], - ['=OCT2HEX(3, "4")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('0000000A') - expect(engine.getCellValue(adr('A2'))).toEqual('0003') - }) - - it('should fail if the result is longer than the desired length', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX(12123, 2)'], - ['=OCT2HEX(34141, "3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - }) - - it('second argument should not affect negative results', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX(7777777042, 1)'], - ['=OCT2HEX(7777777022, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('FFFFFFFE22') - expect(engine.getCellValue(adr('A2'))).toEqual('FFFFFFFE12') - }) - - it('should allow for numbers from 1 to 10 as second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=OCT2HEX(2, 0)'], - ['=OCT2HEX(2, 12)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueBaseLong)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-odd.spec.ts b/test/unit/interpreter/function-odd.spec.ts deleted file mode 100644 index 774b79102e..0000000000 --- a/test/unit/interpreter/function-odd.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ODD', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ODD()', '=ODD(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ODD(1.3)', '=ODD(2.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3) - expect(engine.getCellValue(adr('B1'))).toBe(3) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ODD(-1.3)', '=ODD(-2.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-3) - expect(engine.getCellValue(adr('B1'))).toBe(-3) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=ODD("42.3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(43) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=ODD(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-or.spec.ts b/test/unit/interpreter/function-or.spec.ts deleted file mode 100644 index 4fb3341ca6..0000000000 --- a/test/unit/interpreter/function-or.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function OR', () => { - it('usage', () => { - const engine = HyperFormula.buildFromArray([ - ['=OR(TRUE())', '=OR(FALSE())', '=OR(FALSE(), TRUE(), FALSE())', '=OR("asdf")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('use coercion #1', () => { - const engine = HyperFormula.buildFromArray([ - ['=OR("TRUE", 0)'], - ['=OR("foo", 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('use coercion #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=OR(A4:B4)'], - ['=OR(C4:D4)'], - ['=OR(C4:D4, "foo")'], - ['TRUE', 1, 'foo', '=TRUE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('function OR with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=OR(1)', '=OR(0)', '=OR(FALSE(), 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('C1'))).toBe(true) - }) - - it('function OR takes at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=OR()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('if error in range found, returns first one in row-by-row order', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '=4/0'], - ['=FOOBAR()', '1'], - ['=OR(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '0'], - ['0', '1'], - ['=OR(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(true) - }) - - it('is computed eagerly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['0', '1'], - ['=OR(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when called with a range, ignores strings other than "true", "false" and ""', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', '=TRUE()', '=OR(A1:B1)'], - ['foo', '=FALSE()', '=OR(A2:B2)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(true) - expect(engine.getCellValue(adr('C2'))).toEqual(false) - }) -}) diff --git a/test/unit/interpreter/function-pduration.spec.ts b/test/unit/interpreter/function-pduration.spec.ts deleted file mode 100644 index 657fa1df9d..0000000000 --- a/test/unit/interpreter/function-pduration.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PDURATION', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=PDURATION(1,1)', '=PDURATION(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=PDURATION(2%, 12, 24)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(35.00278878, 6) - }) - - it('should return proper error', () => { - const engine = HyperFormula.buildFromArray([ - ['=PDURATION(-1, 12, 24)'], - ['=PDURATION(2%, -12, -24)'], - ['=PDURATION(0, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-phi.spec.ts b/test/unit/interpreter/function-phi.spec.ts deleted file mode 100644 index 7998c14641..0000000000 --- a/test/unit/interpreter/function-phi.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PHI', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=PHI()'], - ['=PHI(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=PHI("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=PHI(-0.5)'], - ['=PHI(0)'], - ['=PHI(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.3520653267643, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.398942280401433, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.241970724519143, 6) - }) -}) diff --git a/test/unit/interpreter/function-pi.spec.ts b/test/unit/interpreter/function-pi.spec.ts deleted file mode 100644 index 5511347783..0000000000 --- a/test/unit/interpreter/function-pi.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PI', () => { - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=PI(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - it('should return PI with proper precision', () => { - const engine = HyperFormula.buildFromArray([ - ['=PI()'], - ], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(3.14159265358979) - }) -}) diff --git a/test/unit/interpreter/function-pmt.spec.ts b/test/unit/interpreter/function-pmt.spec.ts deleted file mode 100644 index cc919ba94e..0000000000 --- a/test/unit/interpreter/function-pmt.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PMT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=PMT(1,1)', '=PMT(1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=PMT(1%, 360, 10000)', '=PMT(1%, 360, 10000, 1000)', '=PMT(1%, 360, 10000, 1000, 1)'], - ['=PMT(0, 360, 10000)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-102.86125969255) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-103.147385661805) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(-102.126124417629) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-27.777777777777) - }) - - it('should be possible to implement a mortgage calculator', () => { - // Create a HyperFormula instance - const hf = HyperFormula.buildEmpty({ licenseKey: 'gpl-v3' }) - - // Add an empty sheet - const sheetName = hf.addSheet('Mortgage Calculator') - const sheetId = hf.getSheetId(sheetName)! - - // Enter the mortgage parameters - hf.addNamedExpression('AnnualInterestRate', '8%') - hf.addNamedExpression('NumberOfMonths', 10) - hf.addNamedExpression('LoanAmount', 10000) - - // Use the PMT function to calculate the monthly payment - hf.setCellContents({ sheet: sheetId, row: 0, col: 0 }, [['Monthly Payment', '=PMT(AnnualInterestRate/12, NumberOfMonths, -LoanAmount)']]) - - // Display the result - expect(hf.getCellValue({ sheet: sheetId, row: 0, col: 1 })).toBeCloseTo(1037.03) - }) -}) diff --git a/test/unit/interpreter/function-poisson.dist.spec.ts b/test/unit/interpreter/function-poisson.dist.spec.ts deleted file mode 100644 index e85a1eb8a4..0000000000 --- a/test/unit/interpreter/function-poisson.dist.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function POISSON.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=POISSON.DIST(1, 2)'], - ['=POISSON.DIST(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=POISSON.DIST("foo", 2, TRUE())'], - ['=POISSON.DIST(1, "baz", TRUE())'], - ['=POISSON.DIST(1, 2, "BCD")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=POISSON.DIST(10, 1, TRUE())'], - ['=POISSON.DIST(5, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.999999989952234, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.983436391519386, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=POISSON.DIST(10, 1, FALSE())'], - ['=POISSON.DIST(5, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1')) as number / 1.0137771196303e-7).toBeCloseTo(1, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0360894088630967, 6) - }) - - it('should truncate first arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=POISSON.DIST(10.9, 1, TRUE())'], - ['=POISSON.DIST(5.9, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.999999989952234, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.983436391519386, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=POISSON.DIST(0, 0, FALSE())'], - ['=POISSON.DIST(-0.01, 0, FALSE())'], - ['=POISSON.DIST(0, -0.01, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - //product #1 returns value - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - //product #2 returns value - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-power.spec.ts b/test/unit/interpreter/function-power.spec.ts deleted file mode 100644 index 93f5ece844..0000000000 --- a/test/unit/interpreter/function-power.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function POWER', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=POWER(101)'], - ['=POWER(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=POWER(1, "foo")'], - ['=POWER("bar", 4)'], - ['=POWER("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return 1 for 0^0', () => { - const engine = HyperFormula.buildFromArray([ - ['=POWER(0, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should return error for 0^N where N<0', () => { - const engine = HyperFormula.buildFromArray([ - ['=POWER(0, -2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('should return error when result too large or too small', () => { - const engine = HyperFormula.buildFromArray([ - ['=POWER(2, 1023)'], - ['=POWER(2, 1024)'], - ['=POWER(-2, 1023)'], - ['=POWER(-2, 1024)'], - ], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(8.98846567431158e+307) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A3'))).toEqual(-8.98846567431158e+307) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=POWER(0, 1)'], - ['=POWER(2, 0)'], - ['=POWER(2.4, 2.5)'], - ['=POWER(3, -2.5)'], - ], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(8.923353629661888) - expect(engine.getCellValue(adr('A4'))).toEqual(0.06415002990995841) - }) -}) diff --git a/test/unit/interpreter/function-ppmt.spec.ts b/test/unit/interpreter/function-ppmt.spec.ts deleted file mode 100644 index 177e29c04b..0000000000 --- a/test/unit/interpreter/function-ppmt.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PPMT', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=PPMT(1,1)', '=PPMT(1, 1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=PPMT(1%, 1, 360, 10000)', '=PPMT(1%, 1, 360, 10000, 3000)', '=PPMT(1%, 1, 360, 10000, 3000, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-2.86125969255043) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-3.71963760031556) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(-102.692710495362) - }) -}) diff --git a/test/unit/interpreter/function-product.spec.ts b/test/unit/interpreter/function-product.spec.ts deleted file mode 100644 index 21152e71e9..0000000000 --- a/test/unit/interpreter/function-product.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PRODUCT', () => { - it('should take at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=PRODUCT()'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate product', () => { - const engine = HyperFormula.buildFromArray([ - ['=PRODUCT(2, 3)'], - ['=PRODUCT(B2:D2, E2, F2)', 2, 3, 'foo', 'bar', 4], - ['=PRODUCT(5, "foo")'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(24) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) -}) diff --git a/test/unit/interpreter/function-proper.spec.ts b/test/unit/interpreter/function-proper.spec.ts deleted file mode 100644 index cb810c27c4..0000000000 --- a/test/unit/interpreter/function-proper.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PROPER', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=PROPER()'], - ['=PROPER("foo", "bar")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=PROPER("foo")'], - ['=PROPER("foo bar")'], - ['=PROPER(" foo bar ")'], - ['=PROPER("fOo BAR")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('Foo') - expect(engine.getCellValue(adr('A2'))).toEqual('Foo Bar') - expect(engine.getCellValue(adr('A3'))).toEqual(' Foo Bar ') - expect(engine.getCellValue(adr('A4'))).toEqual('Foo Bar') - }) - - it('should work with punctuation marks and numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=PROPER("123aa123bb.cc.dd")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('123Aa123Bb.Cc.Dd') - }) - - it('should work with accents', () => { - const engine = HyperFormula.buildFromArray([ - ['=PROPER("MAI ANH ĐỨC")'], - ['=PROPER("MAI CHÍ THỌ")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('Mai Anh Đức') - expect(engine.getCellValue(adr('A2'))).toEqual('Mai Chí Thọ') - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=PROPER(1)'], - ['=PROPER(5+5)'], - ['=PROPER(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('10') - expect(engine.getCellValue(adr('A3'))).toEqual('True') - }) -}) diff --git a/test/unit/interpreter/function-pv.spec.ts b/test/unit/interpreter/function-pv.spec.ts deleted file mode 100644 index cafc26d3da..0000000000 --- a/test/unit/interpreter/function-pv.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function PV', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=PV(1,1)', '=PV(1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=PV(2%, 24, 100)', '=PV(2%, 24, 100, 400)', '=PV(2%, 24, 100, 400, 1)'], - ['=PV(-99%, 24, 100)', '=PV(-1, 24, 100, 400)', '=PV(-2, 24, 100, 400, 1)'], - ['=PV(0, 24, 100)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-1891.39256, 6) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-2140.081155, 5) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(-2177.909007, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-1.01010101010099e+50, -39) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C2'))).toBeCloseTo(-400, 6) - expect(engine.getCellValue(adr('A3'))).toEqual(-2400) - }) - - it('should return error when args are incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=PV(-1, 0, 100, 400)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM)) - }) -}) diff --git a/test/unit/interpreter/function-quotient.spec.ts b/test/unit/interpreter/function-quotient.spec.ts deleted file mode 100644 index 1966994fd0..0000000000 --- a/test/unit/interpreter/function-quotient.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function QUOTIENT', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=QUOTIENT(101)'], - ['=QUOTIENT(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=QUOTIENT(1, "foo")'], - ['=QUOTIENT("bar", 4)'], - ['=QUOTIENT("foo", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return error when dividing by 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=QUOTIENT(42, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=QUOTIENT(5, 2)'], - ['=QUOTIENT(36, 6.1)'], - ['=QUOTIENT(10.5, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('should work for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=QUOTIENT(-5, 2)'], - ['=QUOTIENT(5, -2)'], - ['=QUOTIENT(-5, -2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-2) - expect(engine.getCellValue(adr('A2'))).toEqual(-2) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/function-radians.spec.ts b/test/unit/interpreter/function-radians.spec.ts deleted file mode 100644 index bbade02daf..0000000000 --- a/test/unit/interpreter/function-radians.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function RADIANS', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([ - ['=RADIANS(0)', '=RADIANS(180.0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(3.1415) - }) - - it('given wrong argument type', () => { - const engine = HyperFormula.buildFromArray([ - ['=RADIANS("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="180"', '=RADIANS(A1)'], - ['=TRUE()', '=RADIANS(A2)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(3.1415) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(0.017453292519943295) - }) - - it('given wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=RADIANS()'], - ['=RADIANS(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=RADIANS(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-rand.spec.ts b/test/unit/interpreter/function-rand.spec.ts deleted file mode 100644 index bc429d60fb..0000000000 --- a/test/unit/interpreter/function-rand.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - function RAND', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=RAND()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeGreaterThanOrEqual(0.0) - expect(engine.getCellValue(adr('A1'))).toBeLessThan(1.0) - }) - - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=RAND(42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) -}) diff --git a/test/unit/interpreter/function-randbetween.spec.ts b/test/unit/interpreter/function-randbetween.spec.ts deleted file mode 100644 index 3726a7e5ff..0000000000 --- a/test/unit/interpreter/function-randbetween.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - function RANDBETWEEN', () => { - it('works with regular input', () => { - const arr: number[] = Array(10).fill(0) - for (let i = 0; i < 100; i++) { - const engine = HyperFormula.buildFromArray([ - ['=RANDBETWEEN(0,9)'], - ]) - const val = engine.getCellValue(adr('A1')) as number - expect(val).toBeGreaterThanOrEqual(0) - expect(val).toBeLessThanOrEqual(9) - expect(val).toEqual(Math.trunc(val)) - arr[val] += 1 - } - for (const val of arr) { - expect(val).toBeGreaterThan(0) // 10*9^100/10^100 ~= 0.0003 chance of failure if truly random - } - }) - - it('rounds arguments', () => { - const arr: number[] = Array(10).fill(0) - for (let i = 0; i < 100; i++) { - const engine = HyperFormula.buildFromArray([ - ['=RANDBETWEEN(-0.1,9.9)'], - ]) - const val = engine.getCellValue(adr('A1')) as number - expect(val).toBeGreaterThanOrEqual(0) - expect(val).toBeLessThanOrEqual(9) - expect(val).toEqual(Math.trunc(val)) - arr[val] += 1 - } - for (const val of arr) { - expect(val).toBeGreaterThan(0) - } - }) - - it('should work for short intervals', () => { - for (let i = 0; i < 10; i++) { - const engine = HyperFormula.buildFromArray([ - ['=RANDBETWEEN(0,0.5)'], - ]) - const val = engine.getCellValue(adr('A1')) as number - expect(val).toEqual(0) - } - }) - - it('should work for short intervals #2', () => { - for (let i = 0; i < 10; i++) { - const engine = HyperFormula.buildFromArray([ - ['=RANDBETWEEN(0.5,1)'], - ]) - const val = engine.getCellValue(adr('A1')) as number - expect(val).toEqual(1) - } - }) - - it('should work for short intervals #3', () => { - for (let i = 0; i < 10; i++) { - const engine = HyperFormula.buildFromArray([ - ['=RANDBETWEEN(0.5,0.6)'], - ]) - const val = engine.getCellValue(adr('A1')) as number - expect(val).toEqual(1) - } - }) - - it('validates bounds on arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=RANDBETWEEN(0.7,0.5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WrongOrder)) - }) - - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=RANDBETWEEN(42)'], - ['=RANDBETWEEN(1,2,3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) -}) diff --git a/test/unit/interpreter/function-rate.spec.ts b/test/unit/interpreter/function-rate.spec.ts deleted file mode 100644 index 39f542cd69..0000000000 --- a/test/unit/interpreter/function-rate.spec.ts +++ /dev/null @@ -1,233 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function RATE', () => { - const requiredFinancialPrecision = 6 // epsilon = 0.0000005 - - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(1,1)', '=RATE(1, 1, 1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return #NUM if algorithm does not converge', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 100)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM)) - }) - - it('should return #VALUE if guess param is invalid', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 400, 0, 0, -1)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE)) - }) - - it('should set the value type to percent', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 400)', ], - ]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - describe('should compute the correct result when type = 0 for', () => { - it('(12, -100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 400)', ], - ['=RATE(12, -100, 400, 0, 0)', ], - ['=RATE(12, -100, 400, 100, 0)', ], - ['=RATE(12, -100, 400, -100, 0)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.228933, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.228933, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.222595, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(0.234770, requiredFinancialPrecision) - }) - - it('(12, 100, -400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, 100, -400)', ], - ['=RATE(12, 100, -400, 0, 0)', ], - ['=RATE(12, 100, -400, 100, 0)', ], - ['=RATE(12, 100, -400, -100, 0)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.228933, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.228933, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.234770, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(0.222595, requiredFinancialPrecision) - }) - - it('(12, 100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, 100, 400, -2000, 0)', ], - ['=RATE(12, 100, 400, -1000, 0)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.030711, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-0.069686, requiredFinancialPrecision) - }) - - it('(0.9, -100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(0.9, -100, 400)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-0.796172, requiredFinancialPrecision) - }) - - it('(300, -465.96, 100000)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(300, -465.96, 100000)'], - ['=RATE(300, -465.96, 100000, 0, 0)'], - ['=RATE(300, -465.96, 100000, 0, 0, 0.008)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.002367, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.002367, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.002367, requiredFinancialPrecision) - }) - - it('(200, -500, 200000)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(200, -500, 200000)'], - ['=RATE(200, -500, 200000, 0, 0)'], - ['=RATE(200, -500, 200000, 0, 0, -0.001)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-0.006237, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-0.006237, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.006237, requiredFinancialPrecision) - }) - }) - - describe('should compute the correct result when type = 1 for', () => { - it('(12, -100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 400, 100, 1)', ], - ['=RATE(12, -100, 400, 1, 1)', ], - ['=RATE(12, -100, 400, 0, 1)', ], - ['=RATE(12, -100, 400, 0, 1, 0.317)', ], - ['=RATE(12, -100, 400, -100, 1)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-0.499693, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-0.990099, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-1.000000, requiredFinancialPrecision) // noted in known-limitations - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(0.3172435, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM)) - }) - - it('(12, -100, 600)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 600, 0, 1)', ], - ['=RATE(12, -100, 600, 100, 1)', ], - ['=RATE(12, -100, 600, -100, 1)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.161450, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.152452, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.169426, requiredFinancialPrecision) - }) - - it('(12, 100, -600)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, 100, -600, 0, 1)', ], - ['=RATE(12, 100, -600, 100, 1)', ], - ['=RATE(12, 100, -600, -100, 1)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.161450, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.169426, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.152452, requiredFinancialPrecision) - }) - - it('(12, 100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, 100, 400, -2000, 1)', ], - ['=RATE(12, 100, 400, -1000, 1)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.028023, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-0.061540, requiredFinancialPrecision) - }) - }) - - describe('should compute the correct result when guess is provided for', () => { - it('(12, -100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 400, 0, 0, 0.23)', ], - ['=RATE(12, -100, 400, 100, 0, 0.22)', ], - ['=RATE(12, -100, 400, -100, 0, 0.23)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.228933, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.222595, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.234770, requiredFinancialPrecision) - }) - - it('(12, -100, 600)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, -100, 600, 0, 1, 0.16)', ], - ['=RATE(12, -100, 600, 100, 1, 0.1)', ], - ['=RATE(12, -100, 600, -100, 1, 0.2)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.161450, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.152452, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.169426, requiredFinancialPrecision) - }) - - it('(12, 100, -400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, 100, -400, 0, 0, 0.23)', ], - ['=RATE(12, 100, -400, 100, 0, 0.23)', ], - ['=RATE(12, 100, -400, -100, 0, 0.22)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.228933, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.234770, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.222595, requiredFinancialPrecision) - }) - - it('(12, 100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(12, 100, 400, -2000, 0, 0.03)', ], - ['=RATE(12, 100, 400, -1000, 0, -0.07)', ], - ['=RATE(12, 100, 400, -2000, 1, 0.01)', ], - ['=RATE(12, 100, 400, -1000, 1, -0.01)', ], - ['=RATE(12, 100, 400, -1000, 1, -0.0000001)', ], - ['=RATE(12, 100, 400, -1000, 1, -0.00000001)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.030711, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-0.069686, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.028023, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(-0.061540, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(-0.061540, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(-0.061540, requiredFinancialPrecision) - }) - - it('(0.9, -100, 400)', () => { - const engine = HyperFormula.buildFromArray([ - ['=RATE(0.9, -100, 400, 0, 0, -0.8)', ], - ['=RATE(0.9, -100, 400, 0, 0, -0.0000001)', ], - ['=RATE(0.9, -100, 400, 0, 0, -0.00000001)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-0.796172, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(-0.796172, requiredFinancialPrecision) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(-0.796172, requiredFinancialPrecision) - }) - }) -}) diff --git a/test/unit/interpreter/function-replace.spec.ts b/test/unit/interpreter/function-replace.spec.ts deleted file mode 100644 index fba875840c..0000000000 --- a/test/unit/interpreter/function-replace.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function REPLACE', () => { - it('should take 4 parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPLACE("foobar", 1, 2)', ], - ['=REPLACE("foobar", 1, 2, "baz", 3)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should replace characters in text based on given position and number of chars', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPLACE("foobar", 2, 2, "uu")', ], - ['=REPLACE("foobar", 2, 10, "uu")', ], - ['=REPLACE("foobar", 3, 2, "uuuu")', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('fuubar') - expect(engine.getCellValue(adr('A2'))).toEqual('fuu') - expect(engine.getCellValue(adr('A3'))).toEqual('fouuuuar') - }) - - it('should insert text before position if number of chars is 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPLACE("foobar", 4, 0, "uu")', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('foouubar') - }) - - it('should append new text if start position is greater than text length', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPLACE("foobar", 7, 15, "uu")', ], - ['=REPLACE("foobar", 28, 0, "uu")', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('foobaruu') - expect(engine.getCellValue(adr('A2'))).toEqual('foobaruu') - }) - - it('should coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPLACE("foobar", 1, 3, TRUE())', ], - ['=REPLACE(12345, 3, 2, 123)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('TRUEbar') - expect(engine.getCellValue(adr('A2'))).toEqual('121235') - }) - - it('should return #VALUE! if parameters out of range', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPLACE("foobar", 0, 2, TRUE())', ], - ['=REPLACE("foobar", 1, -1, "uu")', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NegativeLength)) - }) - - it('should return value when arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPLACE("foobar", "o", 1, "bar")'], - ['=REPLACE("foobar", 1, "f", "bar")'], - ['=REPLACE(B1:B2, 1, 2, "bar")'], - ['=REPLACE("foobar", 1, 2, B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-rept.spec.ts b/test/unit/interpreter/function-rept.spec.ts deleted file mode 100644 index 1c72d0bc07..0000000000 --- a/test/unit/interpreter/function-rept.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function REPT', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPT()'], - ['=REPT("foo")'], - ['=REPT("foo", 1, 2)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return VALUE when wrong type of second parameter', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPT("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return VALUE when second parameter is less than 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPT("foo", -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NegativeCount)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPT("foo", 0)'], - ['=REPT("foo", 3)'], - ['=REPT(1, 5)'], - ['=REPT(, 5)'], - ['=REPT("Na", 7)&" Batman!"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('foofoofoo') - expect(engine.getCellValue(adr('A3'))).toEqual('11111') - expect(engine.getCellValue(adr('A4'))).toEqual('') - expect(engine.getCellValue(adr('A5'))).toEqual('NaNaNaNaNaNaNa Batman!') - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=REPT(1, 1)'], - ['=REPT(5+5, 1)'], - ['=REPT(TRUE(), 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('10') - expect(engine.getCellValue(adr('A3'))).toEqual('TRUE') - }) -}) diff --git a/test/unit/interpreter/function-right.spec.ts b/test/unit/interpreter/function-right.spec.ts deleted file mode 100644 index 9a64e4e492..0000000000 --- a/test/unit/interpreter/function-right.spec.ts +++ /dev/null @@ -1,77 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function RIGHT', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=RIGHT()'], - ['=RIGHT("foo", 1, 2)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return VALUE when wrong type of second parameter', () => { - const engine = HyperFormula.buildFromArray([ - ['=RIGHT("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work with empty argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=RIGHT(, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - }) - - it('should return one character by default', () => { - const engine = HyperFormula.buildFromArray([ - ['=RIGHT("bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('r') - }) - - it('should return VALUE when second parameter is less than 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=RIGHT("foo", -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NegativeLength)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=RIGHT("", 4)'], - ['=RIGHT("bar", 0)'], - ['=RIGHT("bar", 1)'], - ['=RIGHT("bar", 3)'], - ['=RIGHT("bar", 4)'], - ['=RIGHT(123, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('') - expect(engine.getCellValue(adr('A3'))).toEqual('r') - expect(engine.getCellValue(adr('A4'))).toEqual('bar') - expect(engine.getCellValue(adr('A5'))).toEqual('bar') - expect(engine.getCellValue(adr('A6'))).toEqual('23') - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=RIGHT(1, 1)'], - ['=RIGHT(5+5, 1)'], - ['=RIGHT(TRUE(), 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('0') - expect(engine.getCellValue(adr('A3'))).toEqual('E') - }) -}) diff --git a/test/unit/interpreter/function-roman.spec.ts b/test/unit/interpreter/function-roman.spec.ts deleted file mode 100644 index d0ea814761..0000000000 --- a/test/unit/interpreter/function-roman.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ROMAN', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROMAN()', '=ROMAN(1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should properly truncate values and use defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROMAN(499)'], - ['=ROMAN(499, TRUE())'], - ['=ROMAN(499, FALSE())'], - ['=ROMAN(499.9)'], - ['=ROMAN(499, 1.1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual('CDXCIX') - expect(engine.getCellValue(adr('A2'))).toEqual('CDXCIX') - expect(engine.getCellValue(adr('A3'))).toEqual('ID') - expect(engine.getCellValue(adr('A4'))).toEqual('CDXCIX') - expect(engine.getCellValue(adr('A5'))).toEqual('LDVLIV') - }) - - it('should throw correct error if arguments are out of bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROMAN(0)'], - ['=ROMAN(4000)'], - ['=ROMAN(-1)'], - ['=ROMAN(1, "a")'], - ['=ROMAN(1, 5)'], - ['=ROMAN(1, -1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ValueSmall)) - }) - - it('should output correct value for mode 0', () => { - const engine = HyperFormula.buildFromArray([input(0)]) - expect(engine.getSheetValues(0)).toEqual([mode0]) - }) - - it('should output correct value for mode 1', () => { - const engine = HyperFormula.buildFromArray([input(1)]) - expect(engine.getSheetValues(0)).toEqual([mode1]) - }) - - it('should output correct value for mode 2', () => { - const engine = HyperFormula.buildFromArray([input(2)]) - expect(engine.getSheetValues(0)).toEqual([mode2]) - }) - - it('should output correct value for mode 3', () => { - const engine = HyperFormula.buildFromArray([input(3)]) - expect(engine.getSheetValues(0)).toEqual([mode3]) - }) - - it('should output correct value for mode 4', () => { - const engine = HyperFormula.buildFromArray([input(4)]) - expect(engine.getSheetValues(0)).toEqual([mode4]) - }) -}) - -function input(mode: number) { - const ret = [] - for (let i = 1; i < 4000; i++) { - ret.push(`=ROMAN(${i},${mode})`) - } - return ret -} - -const mode0 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'XLV', 'XLVI', 'XLVII', 'XLVIII', 'XLIX', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'XCV', 'XCVI', 'XCVII', 'XCVIII', 'XCIX', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CXLV', 'CXLVI', 'CXLVII', 'CXLVIII', 'CXLIX', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CXCV', 'CXCVI', 'CXCVII', 'CXCVIII', 'CXCIX', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCXLV', 'CCXLVI', 'CCXLVII', 'CCXLVIII', 'CCXLIX', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCXCV', 'CCXCVI', 'CCXCVII', 'CCXCVIII', 'CCXCIX', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCXLV', 'CCCXLVI', 'CCCXLVII', 'CCCXLVIII', 'CCCXLIX', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCXCV', 'CCCXCVI', 'CCCXCVII', 'CCCXCVIII', 'CCCXCIX', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDXLV', 'CDXLVI', 'CDXLVII', 'CDXLVIII', 'CDXLIX', 'CDL', 'CDLI', 'CDLII', 'CDLIII', 'CDLIV', 'CDLV', 'CDLVI', 'CDLVII', 'CDLVIII', 'CDLIX', 'CDLX', 'CDLXI', 'CDLXII', 'CDLXIII', 'CDLXIV', 'CDLXV', 'CDLXVI', 'CDLXVII', 'CDLXVIII', 'CDLXIX', 'CDLXX', 'CDLXXI', 'CDLXXII', 'CDLXXIII', 'CDLXXIV', 'CDLXXV', 'CDLXXVI', 'CDLXXVII', 'CDLXXVIII', 'CDLXXIX', 'CDLXXX', 'CDLXXXI', 'CDLXXXII', 'CDLXXXIII', 'CDLXXXIV', 'CDLXXXV', 'CDLXXXVI', 'CDLXXXVII', 'CDLXXXVIII', 'CDLXXXIX', 'CDXC', 'CDXCI', 'CDXCII', 'CDXCIII', 'CDXCIV', 'CDXCV', 'CDXCVI', 'CDXCVII', 'CDXCVIII', 'CDXCIX', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DXLV', 'DXLVI', 'DXLVII', 'DXLVIII', 'DXLIX', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DXCV', 'DXCVI', 'DXCVII', 'DXCVIII', 'DXCIX', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCXLV', 'DCXLVI', 'DCXLVII', 'DCXLVIII', 'DCXLIX', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCXCV', 'DCXCVI', 'DCXCVII', 'DCXCVIII', 'DCXCIX', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCXLV', 'DCCXLVI', 'DCCXLVII', 'DCCXLVIII', 'DCCXLIX', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCXCV', 'DCCXCVI', 'DCCXCVII', 'DCCXCVIII', 'DCCXCIX', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCXLV', 'DCCCXLVI', 'DCCCXLVII', 'DCCCXLVIII', 'DCCCXLIX', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCXCV', 'DCCCXCVI', 'DCCCXCVII', 'DCCCXCVIII', 'DCCCXCIX', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMXLV', 'CMXLVI', 'CMXLVII', 'CMXLVIII', 'CMXLIX', 'CML', 'CMLI', 'CMLII', 'CMLIII', 'CMLIV', 'CMLV', 'CMLVI', 'CMLVII', 'CMLVIII', 'CMLIX', 'CMLX', 'CMLXI', 'CMLXII', 'CMLXIII', 'CMLXIV', 'CMLXV', 'CMLXVI', 'CMLXVII', 'CMLXVIII', 'CMLXIX', 'CMLXX', 'CMLXXI', 'CMLXXII', 'CMLXXIII', 'CMLXXIV', 'CMLXXV', 'CMLXXVI', 'CMLXXVII', 'CMLXXVIII', 'CMLXXIX', 'CMLXXX', 'CMLXXXI', 'CMLXXXII', 'CMLXXXIII', 'CMLXXXIV', 'CMLXXXV', 'CMLXXXVI', 'CMLXXXVII', 'CMLXXXVIII', 'CMLXXXIX', 'CMXC', 'CMXCI', 'CMXCII', 'CMXCIII', 'CMXCIV', 'CMXCV', 'CMXCVI', 'CMXCVII', 'CMXCVIII', 'CMXCIX', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MXLV', 'MXLVI', 'MXLVII', 'MXLVIII', 'MXLIX', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MXCV', 'MXCVI', 'MXCVII', 'MXCVIII', 'MXCIX', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCXLV', 'MCXLVI', 'MCXLVII', 'MCXLVIII', 'MCXLIX', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCXCV', 'MCXCVI', 'MCXCVII', 'MCXCVIII', 'MCXCIX', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCXLV', 'MCCXLVI', 'MCCXLVII', 'MCCXLVIII', 'MCCXLIX', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCXCV', 'MCCXCVI', 'MCCXCVII', 'MCCXCVIII', 'MCCXCIX', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCXLV', 'MCCCXLVI', 'MCCCXLVII', 'MCCCXLVIII', 'MCCCXLIX', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCXCV', 'MCCCXCVI', 'MCCCXCVII', 'MCCCXCVIII', 'MCCCXCIX', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDXLV', 'MCDXLVI', 'MCDXLVII', 'MCDXLVIII', 'MCDXLIX', 'MCDL', 'MCDLI', 'MCDLII', 'MCDLIII', 'MCDLIV', 'MCDLV', 'MCDLVI', 'MCDLVII', 'MCDLVIII', 'MCDLIX', 'MCDLX', 'MCDLXI', 'MCDLXII', 'MCDLXIII', 'MCDLXIV', 'MCDLXV', 'MCDLXVI', 'MCDLXVII', 'MCDLXVIII', 'MCDLXIX', 'MCDLXX', 'MCDLXXI', 'MCDLXXII', 'MCDLXXIII', 'MCDLXXIV', 'MCDLXXV', 'MCDLXXVI', 'MCDLXXVII', 'MCDLXXVIII', 'MCDLXXIX', 'MCDLXXX', 'MCDLXXXI', 'MCDLXXXII', 'MCDLXXXIII', 'MCDLXXXIV', 'MCDLXXXV', 'MCDLXXXVI', 'MCDLXXXVII', 'MCDLXXXVIII', 'MCDLXXXIX', 'MCDXC', 'MCDXCI', 'MCDXCII', 'MCDXCIII', 'MCDXCIV', 'MCDXCV', 'MCDXCVI', 'MCDXCVII', 'MCDXCVIII', 'MCDXCIX', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDXLV', 'MDXLVI', 'MDXLVII', 'MDXLVIII', 'MDXLIX', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDXCV', 'MDXCVI', 'MDXCVII', 'MDXCVIII', 'MDXCIX', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCXLV', 'MDCXLVI', 'MDCXLVII', 'MDCXLVIII', 'MDCXLIX', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCXCV', 'MDCXCVI', 'MDCXCVII', 'MDCXCVIII', 'MDCXCIX', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCXLV', 'MDCCXLVI', 'MDCCXLVII', 'MDCCXLVIII', 'MDCCXLIX', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCXCV', 'MDCCXCVI', 'MDCCXCVII', 'MDCCXCVIII', 'MDCCXCIX', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCXLV', 'MDCCCXLVI', 'MDCCCXLVII', 'MDCCCXLVIII', 'MDCCCXLIX', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCXCV', 'MDCCCXCVI', 'MDCCCXCVII', 'MDCCCXCVIII', 'MDCCCXCIX', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMXLV', 'MCMXLVI', 'MCMXLVII', 'MCMXLVIII', 'MCMXLIX', 'MCML', 'MCMLI', 'MCMLII', 'MCMLIII', 'MCMLIV', 'MCMLV', 'MCMLVI', 'MCMLVII', 'MCMLVIII', 'MCMLIX', 'MCMLX', 'MCMLXI', 'MCMLXII', 'MCMLXIII', 'MCMLXIV', 'MCMLXV', 'MCMLXVI', 'MCMLXVII', 'MCMLXVIII', 'MCMLXIX', 'MCMLXX', 'MCMLXXI', 'MCMLXXII', 'MCMLXXIII', 'MCMLXXIV', 'MCMLXXV', 'MCMLXXVI', 'MCMLXXVII', 'MCMLXXVIII', 'MCMLXXIX', 'MCMLXXX', 'MCMLXXXI', 'MCMLXXXII', 'MCMLXXXIII', 'MCMLXXXIV', 'MCMLXXXV', 'MCMLXXXVI', 'MCMLXXXVII', 'MCMLXXXVIII', 'MCMLXXXIX', 'MCMXC', 'MCMXCI', 'MCMXCII', 'MCMXCIII', 'MCMXCIV', 'MCMXCV', 'MCMXCVI', 'MCMXCVII', 'MCMXCVIII', 'MCMXCIX', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMXLV', 'MMXLVI', 'MMXLVII', 'MMXLVIII', 'MMXLIX', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMXCV', 'MMXCVI', 'MMXCVII', 'MMXCVIII', 'MMXCIX', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCXLV', 'MMCXLVI', 'MMCXLVII', 'MMCXLVIII', 'MMCXLIX', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCXCV', 'MMCXCVI', 'MMCXCVII', 'MMCXCVIII', 'MMCXCIX', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCXLV', 'MMCCXLVI', 'MMCCXLVII', 'MMCCXLVIII', 'MMCCXLIX', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCXCV', 'MMCCXCVI', 'MMCCXCVII', 'MMCCXCVIII', 'MMCCXCIX', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCXLV', 'MMCCCXLVI', 'MMCCCXLVII', 'MMCCCXLVIII', 'MMCCCXLIX', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCXCV', 'MMCCCXCVI', 'MMCCCXCVII', 'MMCCCXCVIII', 'MMCCCXCIX', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDXLV', 'MMCDXLVI', 'MMCDXLVII', 'MMCDXLVIII', 'MMCDXLIX', 'MMCDL', 'MMCDLI', 'MMCDLII', 'MMCDLIII', 'MMCDLIV', 'MMCDLV', 'MMCDLVI', 'MMCDLVII', 'MMCDLVIII', 'MMCDLIX', 'MMCDLX', 'MMCDLXI', 'MMCDLXII', 'MMCDLXIII', 'MMCDLXIV', 'MMCDLXV', 'MMCDLXVI', 'MMCDLXVII', 'MMCDLXVIII', 'MMCDLXIX', 'MMCDLXX', 'MMCDLXXI', 'MMCDLXXII', 'MMCDLXXIII', 'MMCDLXXIV', 'MMCDLXXV', 'MMCDLXXVI', 'MMCDLXXVII', 'MMCDLXXVIII', 'MMCDLXXIX', 'MMCDLXXX', 'MMCDLXXXI', 'MMCDLXXXII', 'MMCDLXXXIII', 'MMCDLXXXIV', 'MMCDLXXXV', 'MMCDLXXXVI', 'MMCDLXXXVII', 'MMCDLXXXVIII', 'MMCDLXXXIX', 'MMCDXC', 'MMCDXCI', 'MMCDXCII', 'MMCDXCIII', 'MMCDXCIV', 'MMCDXCV', 'MMCDXCVI', 'MMCDXCVII', 'MMCDXCVIII', 'MMCDXCIX', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDXLV', 'MMDXLVI', 'MMDXLVII', 'MMDXLVIII', 'MMDXLIX', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDXCV', 'MMDXCVI', 'MMDXCVII', 'MMDXCVIII', 'MMDXCIX', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCXLV', 'MMDCXLVI', 'MMDCXLVII', 'MMDCXLVIII', 'MMDCXLIX', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCXCV', 'MMDCXCVI', 'MMDCXCVII', 'MMDCXCVIII', 'MMDCXCIX', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCXLV', 'MMDCCXLVI', 'MMDCCXLVII', 'MMDCCXLVIII', 'MMDCCXLIX', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCXCV', 'MMDCCXCVI', 'MMDCCXCVII', 'MMDCCXCVIII', 'MMDCCXCIX', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCXLV', 'MMDCCCXLVI', 'MMDCCCXLVII', 'MMDCCCXLVIII', 'MMDCCCXLIX', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCXCV', 'MMDCCCXCVI', 'MMDCCCXCVII', 'MMDCCCXCVIII', 'MMDCCCXCIX', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMXLV', 'MMCMXLVI', 'MMCMXLVII', 'MMCMXLVIII', 'MMCMXLIX', 'MMCML', 'MMCMLI', 'MMCMLII', 'MMCMLIII', 'MMCMLIV', 'MMCMLV', 'MMCMLVI', 'MMCMLVII', 'MMCMLVIII', 'MMCMLIX', 'MMCMLX', 'MMCMLXI', 'MMCMLXII', 'MMCMLXIII', 'MMCMLXIV', 'MMCMLXV', 'MMCMLXVI', 'MMCMLXVII', 'MMCMLXVIII', 'MMCMLXIX', 'MMCMLXX', 'MMCMLXXI', 'MMCMLXXII', 'MMCMLXXIII', 'MMCMLXXIV', 'MMCMLXXV', 'MMCMLXXVI', 'MMCMLXXVII', 'MMCMLXXVIII', 'MMCMLXXIX', 'MMCMLXXX', 'MMCMLXXXI', 'MMCMLXXXII', 'MMCMLXXXIII', 'MMCMLXXXIV', 'MMCMLXXXV', 'MMCMLXXXVI', 'MMCMLXXXVII', 'MMCMLXXXVIII', 'MMCMLXXXIX', 'MMCMXC', 'MMCMXCI', 'MMCMXCII', 'MMCMXCIII', 'MMCMXCIV', 'MMCMXCV', 'MMCMXCVI', 'MMCMXCVII', 'MMCMXCVIII', 'MMCMXCIX', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMXLV', 'MMMXLVI', 'MMMXLVII', 'MMMXLVIII', 'MMMXLIX', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMXCV', 'MMMXCVI', 'MMMXCVII', 'MMMXCVIII', 'MMMXCIX', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCXLV', 'MMMCXLVI', 'MMMCXLVII', 'MMMCXLVIII', 'MMMCXLIX', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCXCV', 'MMMCXCVI', 'MMMCXCVII', 'MMMCXCVIII', 'MMMCXCIX', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCXLV', 'MMMCCXLVI', 'MMMCCXLVII', 'MMMCCXLVIII', 'MMMCCXLIX', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCXCV', 'MMMCCXCVI', 'MMMCCXCVII', 'MMMCCXCVIII', 'MMMCCXCIX', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCXLV', 'MMMCCCXLVI', 'MMMCCCXLVII', 'MMMCCCXLVIII', 'MMMCCCXLIX', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCXCV', 'MMMCCCXCVI', 'MMMCCCXCVII', 'MMMCCCXCVIII', 'MMMCCCXCIX', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDXLV', 'MMMCDXLVI', 'MMMCDXLVII', 'MMMCDXLVIII', 'MMMCDXLIX', 'MMMCDL', 'MMMCDLI', 'MMMCDLII', 'MMMCDLIII', 'MMMCDLIV', 'MMMCDLV', 'MMMCDLVI', 'MMMCDLVII', 'MMMCDLVIII', 'MMMCDLIX', 'MMMCDLX', 'MMMCDLXI', 'MMMCDLXII', 'MMMCDLXIII', 'MMMCDLXIV', 'MMMCDLXV', 'MMMCDLXVI', 'MMMCDLXVII', 'MMMCDLXVIII', 'MMMCDLXIX', 'MMMCDLXX', 'MMMCDLXXI', 'MMMCDLXXII', 'MMMCDLXXIII', 'MMMCDLXXIV', 'MMMCDLXXV', 'MMMCDLXXVI', 'MMMCDLXXVII', 'MMMCDLXXVIII', 'MMMCDLXXIX', 'MMMCDLXXX', 'MMMCDLXXXI', 'MMMCDLXXXII', 'MMMCDLXXXIII', 'MMMCDLXXXIV', 'MMMCDLXXXV', 'MMMCDLXXXVI', 'MMMCDLXXXVII', 'MMMCDLXXXVIII', 'MMMCDLXXXIX', 'MMMCDXC', 'MMMCDXCI', 'MMMCDXCII', 'MMMCDXCIII', 'MMMCDXCIV', 'MMMCDXCV', 'MMMCDXCVI', 'MMMCDXCVII', 'MMMCDXCVIII', 'MMMCDXCIX', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDXLV', 'MMMDXLVI', 'MMMDXLVII', 'MMMDXLVIII', 'MMMDXLIX', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDXCV', 'MMMDXCVI', 'MMMDXCVII', 'MMMDXCVIII', 'MMMDXCIX', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCXLV', 'MMMDCXLVI', 'MMMDCXLVII', 'MMMDCXLVIII', 'MMMDCXLIX', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCXCV', 'MMMDCXCVI', 'MMMDCXCVII', 'MMMDCXCVIII', 'MMMDCXCIX', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCXLV', 'MMMDCCXLVI', 'MMMDCCXLVII', 'MMMDCCXLVIII', 'MMMDCCXLIX', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCXCV', 'MMMDCCXCVI', 'MMMDCCXCVII', 'MMMDCCXCVIII', 'MMMDCCXCIX', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCXLV', 'MMMDCCCXLVI', 'MMMDCCCXLVII', 'MMMDCCCXLVIII', 'MMMDCCCXLIX', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCXCV', 'MMMDCCCXCVI', 'MMMDCCCXCVII', 'MMMDCCCXCVIII', 'MMMDCCCXCIX', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMXLV', 'MMMCMXLVI', 'MMMCMXLVII', 'MMMCMXLVIII', 'MMMCMXLIX', 'MMMCML', 'MMMCMLI', 'MMMCMLII', 'MMMCMLIII', 'MMMCMLIV', 'MMMCMLV', 'MMMCMLVI', 'MMMCMLVII', 'MMMCMLVIII', 'MMMCMLIX', 'MMMCMLX', 'MMMCMLXI', 'MMMCMLXII', 'MMMCMLXIII', 'MMMCMLXIV', 'MMMCMLXV', 'MMMCMLXVI', 'MMMCMLXVII', 'MMMCMLXVIII', 'MMMCMLXIX', 'MMMCMLXX', 'MMMCMLXXI', 'MMMCMLXXII', 'MMMCMLXXIII', 'MMMCMLXXIV', 'MMMCMLXXV', 'MMMCMLXXVI', 'MMMCMLXXVII', 'MMMCMLXXVIII', 'MMMCMLXXIX', 'MMMCMLXXX', 'MMMCMLXXXI', 'MMMCMLXXXII', 'MMMCMLXXXIII', 'MMMCMLXXXIV', 'MMMCMLXXXV', 'MMMCMLXXXVI', 'MMMCMLXXXVII', 'MMMCMLXXXVIII', 'MMMCMLXXXIX', 'MMMCMXC', 'MMMCMXCI', 'MMMCMXCII', 'MMMCMXCIII', 'MMMCMXCIV', 'MMMCMXCV', 'MMMCMXCVI', 'MMMCMXCVII', 'MMMCMXCVIII', 'MMMCMXCIX', ] -const mode1 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'VLIV', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'VCIV', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CVLIV', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CVCIV', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCVLIV', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCVCIV', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCVLIV', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCVCIV', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDVLIV', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'LDXL', 'LDXLI', 'LDXLII', 'LDXLIII', 'LDXLIV', 'LDVL', 'LDVLI', 'LDVLII', 'LDVLIII', 'LDVLIV', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DVLIV', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DVCIV', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCVLIV', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCVCIV', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCVLIV', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCVCIV', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCVLIV', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCVCIV', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMVLIV', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'LMXL', 'LMXLI', 'LMXLII', 'LMXLIII', 'LMXLIV', 'LMVL', 'LMVLI', 'LMVLII', 'LMVLIII', 'LMVLIV', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MVLIV', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MVCIV', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCVLIV', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCVCIV', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCVLIV', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCVCIV', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCVLIV', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCVCIV', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDVLIV', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MLDXL', 'MLDXLI', 'MLDXLII', 'MLDXLIII', 'MLDXLIV', 'MLDVL', 'MLDVLI', 'MLDVLII', 'MLDVLIII', 'MLDVLIV', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDVLIV', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDVCIV', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCVLIV', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCVCIV', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCVLIV', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCVCIV', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCVLIV', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCVCIV', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMVLIV', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MLMXL', 'MLMXLI', 'MLMXLII', 'MLMXLIII', 'MLMXLIV', 'MLMVL', 'MLMVLI', 'MLMVLII', 'MLMVLIII', 'MLMVLIV', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMVLIV', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMVCIV', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCVLIV', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCVCIV', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCVLIV', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCVCIV', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCVLIV', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCVCIV', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDVLIV', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMLDXL', 'MMLDXLI', 'MMLDXLII', 'MMLDXLIII', 'MMLDXLIV', 'MMLDVL', 'MMLDVLI', 'MMLDVLII', 'MMLDVLIII', 'MMLDVLIV', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDVLIV', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDVCIV', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCVLIV', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCVCIV', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCVLIV', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCVCIV', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCVLIV', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCVCIV', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMVLIV', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMLMXL', 'MMLMXLI', 'MMLMXLII', 'MMLMXLIII', 'MMLMXLIV', 'MMLMVL', 'MMLMVLI', 'MMLMVLII', 'MMLMVLIII', 'MMLMVLIV', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMVLIV', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMVCIV', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCVLIV', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCVCIV', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCVLIV', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCVCIV', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCVLIV', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCVCIV', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDVLIV', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMLDXL', 'MMMLDXLI', 'MMMLDXLII', 'MMMLDXLIII', 'MMMLDXLIV', 'MMMLDVL', 'MMMLDVLI', 'MMMLDVLII', 'MMMLDVLIII', 'MMMLDVLIV', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDVLIV', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDVCIV', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCVLIV', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCVCIV', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCVLIV', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCVCIV', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCVLIV', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCVCIV', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMVLIV', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMLMXL', 'MMMLMXLI', 'MMMLMXLII', 'MMMLMXLIII', 'MMMLMXLIV', 'MMMLMVL', 'MMMLMVLI', 'MMMLMVLII', 'MMMLMVLIII', 'MMMLMVLIV', ] -const mode2 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'IL', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'IC', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CIL', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CIC', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCIL', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCIC', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCIL', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCIC', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDIL', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'XD', 'XDI', 'XDII', 'XDIII', 'XDIV', 'XDV', 'XDVI', 'XDVII', 'XDVIII', 'XDIX', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DIL', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DIC', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCIL', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCIC', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCIL', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCIC', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCIL', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCIC', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMIL', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'XM', 'XMI', 'XMII', 'XMIII', 'XMIV', 'XMV', 'XMVI', 'XMVII', 'XMVIII', 'XMIX', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MIL', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MIC', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCIL', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCIC', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCIL', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCIC', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCIL', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCIC', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDIL', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MXD', 'MXDI', 'MXDII', 'MXDIII', 'MXDIV', 'MXDV', 'MXDVI', 'MXDVII', 'MXDVIII', 'MXDIX', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDIL', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDIC', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCIL', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCIC', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCIL', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCIC', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCIL', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCIC', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMIL', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MXM', 'MXMI', 'MXMII', 'MXMIII', 'MXMIV', 'MXMV', 'MXMVI', 'MXMVII', 'MXMVIII', 'MXMIX', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMIL', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMIC', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCIL', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCIC', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCIL', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCIC', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCIL', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCIC', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDIL', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMXD', 'MMXDI', 'MMXDII', 'MMXDIII', 'MMXDIV', 'MMXDV', 'MMXDVI', 'MMXDVII', 'MMXDVIII', 'MMXDIX', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDIL', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDIC', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCIL', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCIC', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCIL', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCIC', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCIL', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCIC', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMIL', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMXM', 'MMXMI', 'MMXMII', 'MMXMIII', 'MMXMIV', 'MMXMV', 'MMXMVI', 'MMXMVII', 'MMXMVIII', 'MMXMIX', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMIL', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMIC', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCIL', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCIC', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCIL', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCIC', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCIL', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCIC', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDIL', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMXD', 'MMMXDI', 'MMMXDII', 'MMMXDIII', 'MMMXDIV', 'MMMXDV', 'MMMXDVI', 'MMMXDVII', 'MMMXDVIII', 'MMMXDIX', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDIL', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDIC', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCIL', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCIC', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCIL', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCIC', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCIL', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCIC', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMIL', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMXM', 'MMMXMI', 'MMMXMII', 'MMMXMIII', 'MMMXMIV', 'MMMXMV', 'MMMXMVI', 'MMMXMVII', 'MMMXMVIII', 'MMMXMIX', ] -const mode3 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'IL', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'IC', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CIL', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CIC', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCIL', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCIC', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCIL', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCIC', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDIL', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'XD', 'XDI', 'XDII', 'XDIII', 'XDIV', 'VD', 'VDI', 'VDII', 'VDIII', 'VDIV', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DIL', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DIC', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCIL', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCIC', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCIL', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCIC', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCIL', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCIC', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMIL', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'XM', 'XMI', 'XMII', 'XMIII', 'XMIV', 'VM', 'VMI', 'VMII', 'VMIII', 'VMIV', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MIL', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MIC', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCIL', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCIC', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCIL', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCIC', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCIL', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCIC', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDIL', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MXD', 'MXDI', 'MXDII', 'MXDIII', 'MXDIV', 'MVD', 'MVDI', 'MVDII', 'MVDIII', 'MVDIV', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDIL', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDIC', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCIL', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCIC', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCIL', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCIC', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCIL', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCIC', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMIL', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MXM', 'MXMI', 'MXMII', 'MXMIII', 'MXMIV', 'MVM', 'MVMI', 'MVMII', 'MVMIII', 'MVMIV', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMIL', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMIC', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCIL', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCIC', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCIL', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCIC', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCIL', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCIC', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDIL', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMXD', 'MMXDI', 'MMXDII', 'MMXDIII', 'MMXDIV', 'MMVD', 'MMVDI', 'MMVDII', 'MMVDIII', 'MMVDIV', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDIL', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDIC', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCIL', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCIC', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCIL', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCIC', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCIL', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCIC', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMIL', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMXM', 'MMXMI', 'MMXMII', 'MMXMIII', 'MMXMIV', 'MMVM', 'MMVMI', 'MMVMII', 'MMVMIII', 'MMVMIV', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMIL', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMIC', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCIL', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCIC', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCIL', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCIC', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCIL', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCIC', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDIL', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMXD', 'MMMXDI', 'MMMXDII', 'MMMXDIII', 'MMMXDIV', 'MMMVD', 'MMMVDI', 'MMMVDII', 'MMMVDIII', 'MMMVDIV', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDIL', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDIC', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCIL', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCIC', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCIL', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCIC', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCIL', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCIC', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMIL', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMXM', 'MMMXMI', 'MMMXMII', 'MMMXMIII', 'MMMXMIV', 'MMMVM', 'MMMVMI', 'MMMVMII', 'MMMVMIII', 'MMMVMIV', ] -const mode4 = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII', 'XXIII', 'XXIV', 'XXV', 'XXVI', 'XXVII', 'XXVIII', 'XXIX', 'XXX', 'XXXI', 'XXXII', 'XXXIII', 'XXXIV', 'XXXV', 'XXXVI', 'XXXVII', 'XXXVIII', 'XXXIX', 'XL', 'XLI', 'XLII', 'XLIII', 'XLIV', 'VL', 'VLI', 'VLII', 'VLIII', 'IL', 'L', 'LI', 'LII', 'LIII', 'LIV', 'LV', 'LVI', 'LVII', 'LVIII', 'LIX', 'LX', 'LXI', 'LXII', 'LXIII', 'LXIV', 'LXV', 'LXVI', 'LXVII', 'LXVIII', 'LXIX', 'LXX', 'LXXI', 'LXXII', 'LXXIII', 'LXXIV', 'LXXV', 'LXXVI', 'LXXVII', 'LXXVIII', 'LXXIX', 'LXXX', 'LXXXI', 'LXXXII', 'LXXXIII', 'LXXXIV', 'LXXXV', 'LXXXVI', 'LXXXVII', 'LXXXVIII', 'LXXXIX', 'XC', 'XCI', 'XCII', 'XCIII', 'XCIV', 'VC', 'VCI', 'VCII', 'VCIII', 'IC', 'C', 'CI', 'CII', 'CIII', 'CIV', 'CV', 'CVI', 'CVII', 'CVIII', 'CIX', 'CX', 'CXI', 'CXII', 'CXIII', 'CXIV', 'CXV', 'CXVI', 'CXVII', 'CXVIII', 'CXIX', 'CXX', 'CXXI', 'CXXII', 'CXXIII', 'CXXIV', 'CXXV', 'CXXVI', 'CXXVII', 'CXXVIII', 'CXXIX', 'CXXX', 'CXXXI', 'CXXXII', 'CXXXIII', 'CXXXIV', 'CXXXV', 'CXXXVI', 'CXXXVII', 'CXXXVIII', 'CXXXIX', 'CXL', 'CXLI', 'CXLII', 'CXLIII', 'CXLIV', 'CVL', 'CVLI', 'CVLII', 'CVLIII', 'CIL', 'CL', 'CLI', 'CLII', 'CLIII', 'CLIV', 'CLV', 'CLVI', 'CLVII', 'CLVIII', 'CLIX', 'CLX', 'CLXI', 'CLXII', 'CLXIII', 'CLXIV', 'CLXV', 'CLXVI', 'CLXVII', 'CLXVIII', 'CLXIX', 'CLXX', 'CLXXI', 'CLXXII', 'CLXXIII', 'CLXXIV', 'CLXXV', 'CLXXVI', 'CLXXVII', 'CLXXVIII', 'CLXXIX', 'CLXXX', 'CLXXXI', 'CLXXXII', 'CLXXXIII', 'CLXXXIV', 'CLXXXV', 'CLXXXVI', 'CLXXXVII', 'CLXXXVIII', 'CLXXXIX', 'CXC', 'CXCI', 'CXCII', 'CXCIII', 'CXCIV', 'CVC', 'CVCI', 'CVCII', 'CVCIII', 'CIC', 'CC', 'CCI', 'CCII', 'CCIII', 'CCIV', 'CCV', 'CCVI', 'CCVII', 'CCVIII', 'CCIX', 'CCX', 'CCXI', 'CCXII', 'CCXIII', 'CCXIV', 'CCXV', 'CCXVI', 'CCXVII', 'CCXVIII', 'CCXIX', 'CCXX', 'CCXXI', 'CCXXII', 'CCXXIII', 'CCXXIV', 'CCXXV', 'CCXXVI', 'CCXXVII', 'CCXXVIII', 'CCXXIX', 'CCXXX', 'CCXXXI', 'CCXXXII', 'CCXXXIII', 'CCXXXIV', 'CCXXXV', 'CCXXXVI', 'CCXXXVII', 'CCXXXVIII', 'CCXXXIX', 'CCXL', 'CCXLI', 'CCXLII', 'CCXLIII', 'CCXLIV', 'CCVL', 'CCVLI', 'CCVLII', 'CCVLIII', 'CCIL', 'CCL', 'CCLI', 'CCLII', 'CCLIII', 'CCLIV', 'CCLV', 'CCLVI', 'CCLVII', 'CCLVIII', 'CCLIX', 'CCLX', 'CCLXI', 'CCLXII', 'CCLXIII', 'CCLXIV', 'CCLXV', 'CCLXVI', 'CCLXVII', 'CCLXVIII', 'CCLXIX', 'CCLXX', 'CCLXXI', 'CCLXXII', 'CCLXXIII', 'CCLXXIV', 'CCLXXV', 'CCLXXVI', 'CCLXXVII', 'CCLXXVIII', 'CCLXXIX', 'CCLXXX', 'CCLXXXI', 'CCLXXXII', 'CCLXXXIII', 'CCLXXXIV', 'CCLXXXV', 'CCLXXXVI', 'CCLXXXVII', 'CCLXXXVIII', 'CCLXXXIX', 'CCXC', 'CCXCI', 'CCXCII', 'CCXCIII', 'CCXCIV', 'CCVC', 'CCVCI', 'CCVCII', 'CCVCIII', 'CCIC', 'CCC', 'CCCI', 'CCCII', 'CCCIII', 'CCCIV', 'CCCV', 'CCCVI', 'CCCVII', 'CCCVIII', 'CCCIX', 'CCCX', 'CCCXI', 'CCCXII', 'CCCXIII', 'CCCXIV', 'CCCXV', 'CCCXVI', 'CCCXVII', 'CCCXVIII', 'CCCXIX', 'CCCXX', 'CCCXXI', 'CCCXXII', 'CCCXXIII', 'CCCXXIV', 'CCCXXV', 'CCCXXVI', 'CCCXXVII', 'CCCXXVIII', 'CCCXXIX', 'CCCXXX', 'CCCXXXI', 'CCCXXXII', 'CCCXXXIII', 'CCCXXXIV', 'CCCXXXV', 'CCCXXXVI', 'CCCXXXVII', 'CCCXXXVIII', 'CCCXXXIX', 'CCCXL', 'CCCXLI', 'CCCXLII', 'CCCXLIII', 'CCCXLIV', 'CCCVL', 'CCCVLI', 'CCCVLII', 'CCCVLIII', 'CCCIL', 'CCCL', 'CCCLI', 'CCCLII', 'CCCLIII', 'CCCLIV', 'CCCLV', 'CCCLVI', 'CCCLVII', 'CCCLVIII', 'CCCLIX', 'CCCLX', 'CCCLXI', 'CCCLXII', 'CCCLXIII', 'CCCLXIV', 'CCCLXV', 'CCCLXVI', 'CCCLXVII', 'CCCLXVIII', 'CCCLXIX', 'CCCLXX', 'CCCLXXI', 'CCCLXXII', 'CCCLXXIII', 'CCCLXXIV', 'CCCLXXV', 'CCCLXXVI', 'CCCLXXVII', 'CCCLXXVIII', 'CCCLXXIX', 'CCCLXXX', 'CCCLXXXI', 'CCCLXXXII', 'CCCLXXXIII', 'CCCLXXXIV', 'CCCLXXXV', 'CCCLXXXVI', 'CCCLXXXVII', 'CCCLXXXVIII', 'CCCLXXXIX', 'CCCXC', 'CCCXCI', 'CCCXCII', 'CCCXCIII', 'CCCXCIV', 'CCCVC', 'CCCVCI', 'CCCVCII', 'CCCVCIII', 'CCCIC', 'CD', 'CDI', 'CDII', 'CDIII', 'CDIV', 'CDV', 'CDVI', 'CDVII', 'CDVIII', 'CDIX', 'CDX', 'CDXI', 'CDXII', 'CDXIII', 'CDXIV', 'CDXV', 'CDXVI', 'CDXVII', 'CDXVIII', 'CDXIX', 'CDXX', 'CDXXI', 'CDXXII', 'CDXXIII', 'CDXXIV', 'CDXXV', 'CDXXVI', 'CDXXVII', 'CDXXVIII', 'CDXXIX', 'CDXXX', 'CDXXXI', 'CDXXXII', 'CDXXXIII', 'CDXXXIV', 'CDXXXV', 'CDXXXVI', 'CDXXXVII', 'CDXXXVIII', 'CDXXXIX', 'CDXL', 'CDXLI', 'CDXLII', 'CDXLIII', 'CDXLIV', 'CDVL', 'CDVLI', 'CDVLII', 'CDVLIII', 'CDIL', 'LD', 'LDI', 'LDII', 'LDIII', 'LDIV', 'LDV', 'LDVI', 'LDVII', 'LDVIII', 'LDIX', 'LDX', 'LDXI', 'LDXII', 'LDXIII', 'LDXIV', 'LDXV', 'LDXVI', 'LDXVII', 'LDXVIII', 'LDXIX', 'LDXX', 'LDXXI', 'LDXXII', 'LDXXIII', 'LDXXIV', 'LDXXV', 'LDXXVI', 'LDXXVII', 'LDXXVIII', 'LDXXIX', 'LDXXX', 'LDXXXI', 'LDXXXII', 'LDXXXIII', 'LDXXXIV', 'LDXXXV', 'LDXXXVI', 'LDXXXVII', 'LDXXXVIII', 'LDXXXIX', 'XD', 'XDI', 'XDII', 'XDIII', 'XDIV', 'VD', 'VDI', 'VDII', 'VDIII', 'ID', 'D', 'DI', 'DII', 'DIII', 'DIV', 'DV', 'DVI', 'DVII', 'DVIII', 'DIX', 'DX', 'DXI', 'DXII', 'DXIII', 'DXIV', 'DXV', 'DXVI', 'DXVII', 'DXVIII', 'DXIX', 'DXX', 'DXXI', 'DXXII', 'DXXIII', 'DXXIV', 'DXXV', 'DXXVI', 'DXXVII', 'DXXVIII', 'DXXIX', 'DXXX', 'DXXXI', 'DXXXII', 'DXXXIII', 'DXXXIV', 'DXXXV', 'DXXXVI', 'DXXXVII', 'DXXXVIII', 'DXXXIX', 'DXL', 'DXLI', 'DXLII', 'DXLIII', 'DXLIV', 'DVL', 'DVLI', 'DVLII', 'DVLIII', 'DIL', 'DL', 'DLI', 'DLII', 'DLIII', 'DLIV', 'DLV', 'DLVI', 'DLVII', 'DLVIII', 'DLIX', 'DLX', 'DLXI', 'DLXII', 'DLXIII', 'DLXIV', 'DLXV', 'DLXVI', 'DLXVII', 'DLXVIII', 'DLXIX', 'DLXX', 'DLXXI', 'DLXXII', 'DLXXIII', 'DLXXIV', 'DLXXV', 'DLXXVI', 'DLXXVII', 'DLXXVIII', 'DLXXIX', 'DLXXX', 'DLXXXI', 'DLXXXII', 'DLXXXIII', 'DLXXXIV', 'DLXXXV', 'DLXXXVI', 'DLXXXVII', 'DLXXXVIII', 'DLXXXIX', 'DXC', 'DXCI', 'DXCII', 'DXCIII', 'DXCIV', 'DVC', 'DVCI', 'DVCII', 'DVCIII', 'DIC', 'DC', 'DCI', 'DCII', 'DCIII', 'DCIV', 'DCV', 'DCVI', 'DCVII', 'DCVIII', 'DCIX', 'DCX', 'DCXI', 'DCXII', 'DCXIII', 'DCXIV', 'DCXV', 'DCXVI', 'DCXVII', 'DCXVIII', 'DCXIX', 'DCXX', 'DCXXI', 'DCXXII', 'DCXXIII', 'DCXXIV', 'DCXXV', 'DCXXVI', 'DCXXVII', 'DCXXVIII', 'DCXXIX', 'DCXXX', 'DCXXXI', 'DCXXXII', 'DCXXXIII', 'DCXXXIV', 'DCXXXV', 'DCXXXVI', 'DCXXXVII', 'DCXXXVIII', 'DCXXXIX', 'DCXL', 'DCXLI', 'DCXLII', 'DCXLIII', 'DCXLIV', 'DCVL', 'DCVLI', 'DCVLII', 'DCVLIII', 'DCIL', 'DCL', 'DCLI', 'DCLII', 'DCLIII', 'DCLIV', 'DCLV', 'DCLVI', 'DCLVII', 'DCLVIII', 'DCLIX', 'DCLX', 'DCLXI', 'DCLXII', 'DCLXIII', 'DCLXIV', 'DCLXV', 'DCLXVI', 'DCLXVII', 'DCLXVIII', 'DCLXIX', 'DCLXX', 'DCLXXI', 'DCLXXII', 'DCLXXIII', 'DCLXXIV', 'DCLXXV', 'DCLXXVI', 'DCLXXVII', 'DCLXXVIII', 'DCLXXIX', 'DCLXXX', 'DCLXXXI', 'DCLXXXII', 'DCLXXXIII', 'DCLXXXIV', 'DCLXXXV', 'DCLXXXVI', 'DCLXXXVII', 'DCLXXXVIII', 'DCLXXXIX', 'DCXC', 'DCXCI', 'DCXCII', 'DCXCIII', 'DCXCIV', 'DCVC', 'DCVCI', 'DCVCII', 'DCVCIII', 'DCIC', 'DCC', 'DCCI', 'DCCII', 'DCCIII', 'DCCIV', 'DCCV', 'DCCVI', 'DCCVII', 'DCCVIII', 'DCCIX', 'DCCX', 'DCCXI', 'DCCXII', 'DCCXIII', 'DCCXIV', 'DCCXV', 'DCCXVI', 'DCCXVII', 'DCCXVIII', 'DCCXIX', 'DCCXX', 'DCCXXI', 'DCCXXII', 'DCCXXIII', 'DCCXXIV', 'DCCXXV', 'DCCXXVI', 'DCCXXVII', 'DCCXXVIII', 'DCCXXIX', 'DCCXXX', 'DCCXXXI', 'DCCXXXII', 'DCCXXXIII', 'DCCXXXIV', 'DCCXXXV', 'DCCXXXVI', 'DCCXXXVII', 'DCCXXXVIII', 'DCCXXXIX', 'DCCXL', 'DCCXLI', 'DCCXLII', 'DCCXLIII', 'DCCXLIV', 'DCCVL', 'DCCVLI', 'DCCVLII', 'DCCVLIII', 'DCCIL', 'DCCL', 'DCCLI', 'DCCLII', 'DCCLIII', 'DCCLIV', 'DCCLV', 'DCCLVI', 'DCCLVII', 'DCCLVIII', 'DCCLIX', 'DCCLX', 'DCCLXI', 'DCCLXII', 'DCCLXIII', 'DCCLXIV', 'DCCLXV', 'DCCLXVI', 'DCCLXVII', 'DCCLXVIII', 'DCCLXIX', 'DCCLXX', 'DCCLXXI', 'DCCLXXII', 'DCCLXXIII', 'DCCLXXIV', 'DCCLXXV', 'DCCLXXVI', 'DCCLXXVII', 'DCCLXXVIII', 'DCCLXXIX', 'DCCLXXX', 'DCCLXXXI', 'DCCLXXXII', 'DCCLXXXIII', 'DCCLXXXIV', 'DCCLXXXV', 'DCCLXXXVI', 'DCCLXXXVII', 'DCCLXXXVIII', 'DCCLXXXIX', 'DCCXC', 'DCCXCI', 'DCCXCII', 'DCCXCIII', 'DCCXCIV', 'DCCVC', 'DCCVCI', 'DCCVCII', 'DCCVCIII', 'DCCIC', 'DCCC', 'DCCCI', 'DCCCII', 'DCCCIII', 'DCCCIV', 'DCCCV', 'DCCCVI', 'DCCCVII', 'DCCCVIII', 'DCCCIX', 'DCCCX', 'DCCCXI', 'DCCCXII', 'DCCCXIII', 'DCCCXIV', 'DCCCXV', 'DCCCXVI', 'DCCCXVII', 'DCCCXVIII', 'DCCCXIX', 'DCCCXX', 'DCCCXXI', 'DCCCXXII', 'DCCCXXIII', 'DCCCXXIV', 'DCCCXXV', 'DCCCXXVI', 'DCCCXXVII', 'DCCCXXVIII', 'DCCCXXIX', 'DCCCXXX', 'DCCCXXXI', 'DCCCXXXII', 'DCCCXXXIII', 'DCCCXXXIV', 'DCCCXXXV', 'DCCCXXXVI', 'DCCCXXXVII', 'DCCCXXXVIII', 'DCCCXXXIX', 'DCCCXL', 'DCCCXLI', 'DCCCXLII', 'DCCCXLIII', 'DCCCXLIV', 'DCCCVL', 'DCCCVLI', 'DCCCVLII', 'DCCCVLIII', 'DCCCIL', 'DCCCL', 'DCCCLI', 'DCCCLII', 'DCCCLIII', 'DCCCLIV', 'DCCCLV', 'DCCCLVI', 'DCCCLVII', 'DCCCLVIII', 'DCCCLIX', 'DCCCLX', 'DCCCLXI', 'DCCCLXII', 'DCCCLXIII', 'DCCCLXIV', 'DCCCLXV', 'DCCCLXVI', 'DCCCLXVII', 'DCCCLXVIII', 'DCCCLXIX', 'DCCCLXX', 'DCCCLXXI', 'DCCCLXXII', 'DCCCLXXIII', 'DCCCLXXIV', 'DCCCLXXV', 'DCCCLXXVI', 'DCCCLXXVII', 'DCCCLXXVIII', 'DCCCLXXIX', 'DCCCLXXX', 'DCCCLXXXI', 'DCCCLXXXII', 'DCCCLXXXIII', 'DCCCLXXXIV', 'DCCCLXXXV', 'DCCCLXXXVI', 'DCCCLXXXVII', 'DCCCLXXXVIII', 'DCCCLXXXIX', 'DCCCXC', 'DCCCXCI', 'DCCCXCII', 'DCCCXCIII', 'DCCCXCIV', 'DCCCVC', 'DCCCVCI', 'DCCCVCII', 'DCCCVCIII', 'DCCCIC', 'CM', 'CMI', 'CMII', 'CMIII', 'CMIV', 'CMV', 'CMVI', 'CMVII', 'CMVIII', 'CMIX', 'CMX', 'CMXI', 'CMXII', 'CMXIII', 'CMXIV', 'CMXV', 'CMXVI', 'CMXVII', 'CMXVIII', 'CMXIX', 'CMXX', 'CMXXI', 'CMXXII', 'CMXXIII', 'CMXXIV', 'CMXXV', 'CMXXVI', 'CMXXVII', 'CMXXVIII', 'CMXXIX', 'CMXXX', 'CMXXXI', 'CMXXXII', 'CMXXXIII', 'CMXXXIV', 'CMXXXV', 'CMXXXVI', 'CMXXXVII', 'CMXXXVIII', 'CMXXXIX', 'CMXL', 'CMXLI', 'CMXLII', 'CMXLIII', 'CMXLIV', 'CMVL', 'CMVLI', 'CMVLII', 'CMVLIII', 'CMIL', 'LM', 'LMI', 'LMII', 'LMIII', 'LMIV', 'LMV', 'LMVI', 'LMVII', 'LMVIII', 'LMIX', 'LMX', 'LMXI', 'LMXII', 'LMXIII', 'LMXIV', 'LMXV', 'LMXVI', 'LMXVII', 'LMXVIII', 'LMXIX', 'LMXX', 'LMXXI', 'LMXXII', 'LMXXIII', 'LMXXIV', 'LMXXV', 'LMXXVI', 'LMXXVII', 'LMXXVIII', 'LMXXIX', 'LMXXX', 'LMXXXI', 'LMXXXII', 'LMXXXIII', 'LMXXXIV', 'LMXXXV', 'LMXXXVI', 'LMXXXVII', 'LMXXXVIII', 'LMXXXIX', 'XM', 'XMI', 'XMII', 'XMIII', 'XMIV', 'VM', 'VMI', 'VMII', 'VMIII', 'IM', 'M', 'MI', 'MII', 'MIII', 'MIV', 'MV', 'MVI', 'MVII', 'MVIII', 'MIX', 'MX', 'MXI', 'MXII', 'MXIII', 'MXIV', 'MXV', 'MXVI', 'MXVII', 'MXVIII', 'MXIX', 'MXX', 'MXXI', 'MXXII', 'MXXIII', 'MXXIV', 'MXXV', 'MXXVI', 'MXXVII', 'MXXVIII', 'MXXIX', 'MXXX', 'MXXXI', 'MXXXII', 'MXXXIII', 'MXXXIV', 'MXXXV', 'MXXXVI', 'MXXXVII', 'MXXXVIII', 'MXXXIX', 'MXL', 'MXLI', 'MXLII', 'MXLIII', 'MXLIV', 'MVL', 'MVLI', 'MVLII', 'MVLIII', 'MIL', 'ML', 'MLI', 'MLII', 'MLIII', 'MLIV', 'MLV', 'MLVI', 'MLVII', 'MLVIII', 'MLIX', 'MLX', 'MLXI', 'MLXII', 'MLXIII', 'MLXIV', 'MLXV', 'MLXVI', 'MLXVII', 'MLXVIII', 'MLXIX', 'MLXX', 'MLXXI', 'MLXXII', 'MLXXIII', 'MLXXIV', 'MLXXV', 'MLXXVI', 'MLXXVII', 'MLXXVIII', 'MLXXIX', 'MLXXX', 'MLXXXI', 'MLXXXII', 'MLXXXIII', 'MLXXXIV', 'MLXXXV', 'MLXXXVI', 'MLXXXVII', 'MLXXXVIII', 'MLXXXIX', 'MXC', 'MXCI', 'MXCII', 'MXCIII', 'MXCIV', 'MVC', 'MVCI', 'MVCII', 'MVCIII', 'MIC', 'MC', 'MCI', 'MCII', 'MCIII', 'MCIV', 'MCV', 'MCVI', 'MCVII', 'MCVIII', 'MCIX', 'MCX', 'MCXI', 'MCXII', 'MCXIII', 'MCXIV', 'MCXV', 'MCXVI', 'MCXVII', 'MCXVIII', 'MCXIX', 'MCXX', 'MCXXI', 'MCXXII', 'MCXXIII', 'MCXXIV', 'MCXXV', 'MCXXVI', 'MCXXVII', 'MCXXVIII', 'MCXXIX', 'MCXXX', 'MCXXXI', 'MCXXXII', 'MCXXXIII', 'MCXXXIV', 'MCXXXV', 'MCXXXVI', 'MCXXXVII', 'MCXXXVIII', 'MCXXXIX', 'MCXL', 'MCXLI', 'MCXLII', 'MCXLIII', 'MCXLIV', 'MCVL', 'MCVLI', 'MCVLII', 'MCVLIII', 'MCIL', 'MCL', 'MCLI', 'MCLII', 'MCLIII', 'MCLIV', 'MCLV', 'MCLVI', 'MCLVII', 'MCLVIII', 'MCLIX', 'MCLX', 'MCLXI', 'MCLXII', 'MCLXIII', 'MCLXIV', 'MCLXV', 'MCLXVI', 'MCLXVII', 'MCLXVIII', 'MCLXIX', 'MCLXX', 'MCLXXI', 'MCLXXII', 'MCLXXIII', 'MCLXXIV', 'MCLXXV', 'MCLXXVI', 'MCLXXVII', 'MCLXXVIII', 'MCLXXIX', 'MCLXXX', 'MCLXXXI', 'MCLXXXII', 'MCLXXXIII', 'MCLXXXIV', 'MCLXXXV', 'MCLXXXVI', 'MCLXXXVII', 'MCLXXXVIII', 'MCLXXXIX', 'MCXC', 'MCXCI', 'MCXCII', 'MCXCIII', 'MCXCIV', 'MCVC', 'MCVCI', 'MCVCII', 'MCVCIII', 'MCIC', 'MCC', 'MCCI', 'MCCII', 'MCCIII', 'MCCIV', 'MCCV', 'MCCVI', 'MCCVII', 'MCCVIII', 'MCCIX', 'MCCX', 'MCCXI', 'MCCXII', 'MCCXIII', 'MCCXIV', 'MCCXV', 'MCCXVI', 'MCCXVII', 'MCCXVIII', 'MCCXIX', 'MCCXX', 'MCCXXI', 'MCCXXII', 'MCCXXIII', 'MCCXXIV', 'MCCXXV', 'MCCXXVI', 'MCCXXVII', 'MCCXXVIII', 'MCCXXIX', 'MCCXXX', 'MCCXXXI', 'MCCXXXII', 'MCCXXXIII', 'MCCXXXIV', 'MCCXXXV', 'MCCXXXVI', 'MCCXXXVII', 'MCCXXXVIII', 'MCCXXXIX', 'MCCXL', 'MCCXLI', 'MCCXLII', 'MCCXLIII', 'MCCXLIV', 'MCCVL', 'MCCVLI', 'MCCVLII', 'MCCVLIII', 'MCCIL', 'MCCL', 'MCCLI', 'MCCLII', 'MCCLIII', 'MCCLIV', 'MCCLV', 'MCCLVI', 'MCCLVII', 'MCCLVIII', 'MCCLIX', 'MCCLX', 'MCCLXI', 'MCCLXII', 'MCCLXIII', 'MCCLXIV', 'MCCLXV', 'MCCLXVI', 'MCCLXVII', 'MCCLXVIII', 'MCCLXIX', 'MCCLXX', 'MCCLXXI', 'MCCLXXII', 'MCCLXXIII', 'MCCLXXIV', 'MCCLXXV', 'MCCLXXVI', 'MCCLXXVII', 'MCCLXXVIII', 'MCCLXXIX', 'MCCLXXX', 'MCCLXXXI', 'MCCLXXXII', 'MCCLXXXIII', 'MCCLXXXIV', 'MCCLXXXV', 'MCCLXXXVI', 'MCCLXXXVII', 'MCCLXXXVIII', 'MCCLXXXIX', 'MCCXC', 'MCCXCI', 'MCCXCII', 'MCCXCIII', 'MCCXCIV', 'MCCVC', 'MCCVCI', 'MCCVCII', 'MCCVCIII', 'MCCIC', 'MCCC', 'MCCCI', 'MCCCII', 'MCCCIII', 'MCCCIV', 'MCCCV', 'MCCCVI', 'MCCCVII', 'MCCCVIII', 'MCCCIX', 'MCCCX', 'MCCCXI', 'MCCCXII', 'MCCCXIII', 'MCCCXIV', 'MCCCXV', 'MCCCXVI', 'MCCCXVII', 'MCCCXVIII', 'MCCCXIX', 'MCCCXX', 'MCCCXXI', 'MCCCXXII', 'MCCCXXIII', 'MCCCXXIV', 'MCCCXXV', 'MCCCXXVI', 'MCCCXXVII', 'MCCCXXVIII', 'MCCCXXIX', 'MCCCXXX', 'MCCCXXXI', 'MCCCXXXII', 'MCCCXXXIII', 'MCCCXXXIV', 'MCCCXXXV', 'MCCCXXXVI', 'MCCCXXXVII', 'MCCCXXXVIII', 'MCCCXXXIX', 'MCCCXL', 'MCCCXLI', 'MCCCXLII', 'MCCCXLIII', 'MCCCXLIV', 'MCCCVL', 'MCCCVLI', 'MCCCVLII', 'MCCCVLIII', 'MCCCIL', 'MCCCL', 'MCCCLI', 'MCCCLII', 'MCCCLIII', 'MCCCLIV', 'MCCCLV', 'MCCCLVI', 'MCCCLVII', 'MCCCLVIII', 'MCCCLIX', 'MCCCLX', 'MCCCLXI', 'MCCCLXII', 'MCCCLXIII', 'MCCCLXIV', 'MCCCLXV', 'MCCCLXVI', 'MCCCLXVII', 'MCCCLXVIII', 'MCCCLXIX', 'MCCCLXX', 'MCCCLXXI', 'MCCCLXXII', 'MCCCLXXIII', 'MCCCLXXIV', 'MCCCLXXV', 'MCCCLXXVI', 'MCCCLXXVII', 'MCCCLXXVIII', 'MCCCLXXIX', 'MCCCLXXX', 'MCCCLXXXI', 'MCCCLXXXII', 'MCCCLXXXIII', 'MCCCLXXXIV', 'MCCCLXXXV', 'MCCCLXXXVI', 'MCCCLXXXVII', 'MCCCLXXXVIII', 'MCCCLXXXIX', 'MCCCXC', 'MCCCXCI', 'MCCCXCII', 'MCCCXCIII', 'MCCCXCIV', 'MCCCVC', 'MCCCVCI', 'MCCCVCII', 'MCCCVCIII', 'MCCCIC', 'MCD', 'MCDI', 'MCDII', 'MCDIII', 'MCDIV', 'MCDV', 'MCDVI', 'MCDVII', 'MCDVIII', 'MCDIX', 'MCDX', 'MCDXI', 'MCDXII', 'MCDXIII', 'MCDXIV', 'MCDXV', 'MCDXVI', 'MCDXVII', 'MCDXVIII', 'MCDXIX', 'MCDXX', 'MCDXXI', 'MCDXXII', 'MCDXXIII', 'MCDXXIV', 'MCDXXV', 'MCDXXVI', 'MCDXXVII', 'MCDXXVIII', 'MCDXXIX', 'MCDXXX', 'MCDXXXI', 'MCDXXXII', 'MCDXXXIII', 'MCDXXXIV', 'MCDXXXV', 'MCDXXXVI', 'MCDXXXVII', 'MCDXXXVIII', 'MCDXXXIX', 'MCDXL', 'MCDXLI', 'MCDXLII', 'MCDXLIII', 'MCDXLIV', 'MCDVL', 'MCDVLI', 'MCDVLII', 'MCDVLIII', 'MCDIL', 'MLD', 'MLDI', 'MLDII', 'MLDIII', 'MLDIV', 'MLDV', 'MLDVI', 'MLDVII', 'MLDVIII', 'MLDIX', 'MLDX', 'MLDXI', 'MLDXII', 'MLDXIII', 'MLDXIV', 'MLDXV', 'MLDXVI', 'MLDXVII', 'MLDXVIII', 'MLDXIX', 'MLDXX', 'MLDXXI', 'MLDXXII', 'MLDXXIII', 'MLDXXIV', 'MLDXXV', 'MLDXXVI', 'MLDXXVII', 'MLDXXVIII', 'MLDXXIX', 'MLDXXX', 'MLDXXXI', 'MLDXXXII', 'MLDXXXIII', 'MLDXXXIV', 'MLDXXXV', 'MLDXXXVI', 'MLDXXXVII', 'MLDXXXVIII', 'MLDXXXIX', 'MXD', 'MXDI', 'MXDII', 'MXDIII', 'MXDIV', 'MVD', 'MVDI', 'MVDII', 'MVDIII', 'MID', 'MD', 'MDI', 'MDII', 'MDIII', 'MDIV', 'MDV', 'MDVI', 'MDVII', 'MDVIII', 'MDIX', 'MDX', 'MDXI', 'MDXII', 'MDXIII', 'MDXIV', 'MDXV', 'MDXVI', 'MDXVII', 'MDXVIII', 'MDXIX', 'MDXX', 'MDXXI', 'MDXXII', 'MDXXIII', 'MDXXIV', 'MDXXV', 'MDXXVI', 'MDXXVII', 'MDXXVIII', 'MDXXIX', 'MDXXX', 'MDXXXI', 'MDXXXII', 'MDXXXIII', 'MDXXXIV', 'MDXXXV', 'MDXXXVI', 'MDXXXVII', 'MDXXXVIII', 'MDXXXIX', 'MDXL', 'MDXLI', 'MDXLII', 'MDXLIII', 'MDXLIV', 'MDVL', 'MDVLI', 'MDVLII', 'MDVLIII', 'MDIL', 'MDL', 'MDLI', 'MDLII', 'MDLIII', 'MDLIV', 'MDLV', 'MDLVI', 'MDLVII', 'MDLVIII', 'MDLIX', 'MDLX', 'MDLXI', 'MDLXII', 'MDLXIII', 'MDLXIV', 'MDLXV', 'MDLXVI', 'MDLXVII', 'MDLXVIII', 'MDLXIX', 'MDLXX', 'MDLXXI', 'MDLXXII', 'MDLXXIII', 'MDLXXIV', 'MDLXXV', 'MDLXXVI', 'MDLXXVII', 'MDLXXVIII', 'MDLXXIX', 'MDLXXX', 'MDLXXXI', 'MDLXXXII', 'MDLXXXIII', 'MDLXXXIV', 'MDLXXXV', 'MDLXXXVI', 'MDLXXXVII', 'MDLXXXVIII', 'MDLXXXIX', 'MDXC', 'MDXCI', 'MDXCII', 'MDXCIII', 'MDXCIV', 'MDVC', 'MDVCI', 'MDVCII', 'MDVCIII', 'MDIC', 'MDC', 'MDCI', 'MDCII', 'MDCIII', 'MDCIV', 'MDCV', 'MDCVI', 'MDCVII', 'MDCVIII', 'MDCIX', 'MDCX', 'MDCXI', 'MDCXII', 'MDCXIII', 'MDCXIV', 'MDCXV', 'MDCXVI', 'MDCXVII', 'MDCXVIII', 'MDCXIX', 'MDCXX', 'MDCXXI', 'MDCXXII', 'MDCXXIII', 'MDCXXIV', 'MDCXXV', 'MDCXXVI', 'MDCXXVII', 'MDCXXVIII', 'MDCXXIX', 'MDCXXX', 'MDCXXXI', 'MDCXXXII', 'MDCXXXIII', 'MDCXXXIV', 'MDCXXXV', 'MDCXXXVI', 'MDCXXXVII', 'MDCXXXVIII', 'MDCXXXIX', 'MDCXL', 'MDCXLI', 'MDCXLII', 'MDCXLIII', 'MDCXLIV', 'MDCVL', 'MDCVLI', 'MDCVLII', 'MDCVLIII', 'MDCIL', 'MDCL', 'MDCLI', 'MDCLII', 'MDCLIII', 'MDCLIV', 'MDCLV', 'MDCLVI', 'MDCLVII', 'MDCLVIII', 'MDCLIX', 'MDCLX', 'MDCLXI', 'MDCLXII', 'MDCLXIII', 'MDCLXIV', 'MDCLXV', 'MDCLXVI', 'MDCLXVII', 'MDCLXVIII', 'MDCLXIX', 'MDCLXX', 'MDCLXXI', 'MDCLXXII', 'MDCLXXIII', 'MDCLXXIV', 'MDCLXXV', 'MDCLXXVI', 'MDCLXXVII', 'MDCLXXVIII', 'MDCLXXIX', 'MDCLXXX', 'MDCLXXXI', 'MDCLXXXII', 'MDCLXXXIII', 'MDCLXXXIV', 'MDCLXXXV', 'MDCLXXXVI', 'MDCLXXXVII', 'MDCLXXXVIII', 'MDCLXXXIX', 'MDCXC', 'MDCXCI', 'MDCXCII', 'MDCXCIII', 'MDCXCIV', 'MDCVC', 'MDCVCI', 'MDCVCII', 'MDCVCIII', 'MDCIC', 'MDCC', 'MDCCI', 'MDCCII', 'MDCCIII', 'MDCCIV', 'MDCCV', 'MDCCVI', 'MDCCVII', 'MDCCVIII', 'MDCCIX', 'MDCCX', 'MDCCXI', 'MDCCXII', 'MDCCXIII', 'MDCCXIV', 'MDCCXV', 'MDCCXVI', 'MDCCXVII', 'MDCCXVIII', 'MDCCXIX', 'MDCCXX', 'MDCCXXI', 'MDCCXXII', 'MDCCXXIII', 'MDCCXXIV', 'MDCCXXV', 'MDCCXXVI', 'MDCCXXVII', 'MDCCXXVIII', 'MDCCXXIX', 'MDCCXXX', 'MDCCXXXI', 'MDCCXXXII', 'MDCCXXXIII', 'MDCCXXXIV', 'MDCCXXXV', 'MDCCXXXVI', 'MDCCXXXVII', 'MDCCXXXVIII', 'MDCCXXXIX', 'MDCCXL', 'MDCCXLI', 'MDCCXLII', 'MDCCXLIII', 'MDCCXLIV', 'MDCCVL', 'MDCCVLI', 'MDCCVLII', 'MDCCVLIII', 'MDCCIL', 'MDCCL', 'MDCCLI', 'MDCCLII', 'MDCCLIII', 'MDCCLIV', 'MDCCLV', 'MDCCLVI', 'MDCCLVII', 'MDCCLVIII', 'MDCCLIX', 'MDCCLX', 'MDCCLXI', 'MDCCLXII', 'MDCCLXIII', 'MDCCLXIV', 'MDCCLXV', 'MDCCLXVI', 'MDCCLXVII', 'MDCCLXVIII', 'MDCCLXIX', 'MDCCLXX', 'MDCCLXXI', 'MDCCLXXII', 'MDCCLXXIII', 'MDCCLXXIV', 'MDCCLXXV', 'MDCCLXXVI', 'MDCCLXXVII', 'MDCCLXXVIII', 'MDCCLXXIX', 'MDCCLXXX', 'MDCCLXXXI', 'MDCCLXXXII', 'MDCCLXXXIII', 'MDCCLXXXIV', 'MDCCLXXXV', 'MDCCLXXXVI', 'MDCCLXXXVII', 'MDCCLXXXVIII', 'MDCCLXXXIX', 'MDCCXC', 'MDCCXCI', 'MDCCXCII', 'MDCCXCIII', 'MDCCXCIV', 'MDCCVC', 'MDCCVCI', 'MDCCVCII', 'MDCCVCIII', 'MDCCIC', 'MDCCC', 'MDCCCI', 'MDCCCII', 'MDCCCIII', 'MDCCCIV', 'MDCCCV', 'MDCCCVI', 'MDCCCVII', 'MDCCCVIII', 'MDCCCIX', 'MDCCCX', 'MDCCCXI', 'MDCCCXII', 'MDCCCXIII', 'MDCCCXIV', 'MDCCCXV', 'MDCCCXVI', 'MDCCCXVII', 'MDCCCXVIII', 'MDCCCXIX', 'MDCCCXX', 'MDCCCXXI', 'MDCCCXXII', 'MDCCCXXIII', 'MDCCCXXIV', 'MDCCCXXV', 'MDCCCXXVI', 'MDCCCXXVII', 'MDCCCXXVIII', 'MDCCCXXIX', 'MDCCCXXX', 'MDCCCXXXI', 'MDCCCXXXII', 'MDCCCXXXIII', 'MDCCCXXXIV', 'MDCCCXXXV', 'MDCCCXXXVI', 'MDCCCXXXVII', 'MDCCCXXXVIII', 'MDCCCXXXIX', 'MDCCCXL', 'MDCCCXLI', 'MDCCCXLII', 'MDCCCXLIII', 'MDCCCXLIV', 'MDCCCVL', 'MDCCCVLI', 'MDCCCVLII', 'MDCCCVLIII', 'MDCCCIL', 'MDCCCL', 'MDCCCLI', 'MDCCCLII', 'MDCCCLIII', 'MDCCCLIV', 'MDCCCLV', 'MDCCCLVI', 'MDCCCLVII', 'MDCCCLVIII', 'MDCCCLIX', 'MDCCCLX', 'MDCCCLXI', 'MDCCCLXII', 'MDCCCLXIII', 'MDCCCLXIV', 'MDCCCLXV', 'MDCCCLXVI', 'MDCCCLXVII', 'MDCCCLXVIII', 'MDCCCLXIX', 'MDCCCLXX', 'MDCCCLXXI', 'MDCCCLXXII', 'MDCCCLXXIII', 'MDCCCLXXIV', 'MDCCCLXXV', 'MDCCCLXXVI', 'MDCCCLXXVII', 'MDCCCLXXVIII', 'MDCCCLXXIX', 'MDCCCLXXX', 'MDCCCLXXXI', 'MDCCCLXXXII', 'MDCCCLXXXIII', 'MDCCCLXXXIV', 'MDCCCLXXXV', 'MDCCCLXXXVI', 'MDCCCLXXXVII', 'MDCCCLXXXVIII', 'MDCCCLXXXIX', 'MDCCCXC', 'MDCCCXCI', 'MDCCCXCII', 'MDCCCXCIII', 'MDCCCXCIV', 'MDCCCVC', 'MDCCCVCI', 'MDCCCVCII', 'MDCCCVCIII', 'MDCCCIC', 'MCM', 'MCMI', 'MCMII', 'MCMIII', 'MCMIV', 'MCMV', 'MCMVI', 'MCMVII', 'MCMVIII', 'MCMIX', 'MCMX', 'MCMXI', 'MCMXII', 'MCMXIII', 'MCMXIV', 'MCMXV', 'MCMXVI', 'MCMXVII', 'MCMXVIII', 'MCMXIX', 'MCMXX', 'MCMXXI', 'MCMXXII', 'MCMXXIII', 'MCMXXIV', 'MCMXXV', 'MCMXXVI', 'MCMXXVII', 'MCMXXVIII', 'MCMXXIX', 'MCMXXX', 'MCMXXXI', 'MCMXXXII', 'MCMXXXIII', 'MCMXXXIV', 'MCMXXXV', 'MCMXXXVI', 'MCMXXXVII', 'MCMXXXVIII', 'MCMXXXIX', 'MCMXL', 'MCMXLI', 'MCMXLII', 'MCMXLIII', 'MCMXLIV', 'MCMVL', 'MCMVLI', 'MCMVLII', 'MCMVLIII', 'MCMIL', 'MLM', 'MLMI', 'MLMII', 'MLMIII', 'MLMIV', 'MLMV', 'MLMVI', 'MLMVII', 'MLMVIII', 'MLMIX', 'MLMX', 'MLMXI', 'MLMXII', 'MLMXIII', 'MLMXIV', 'MLMXV', 'MLMXVI', 'MLMXVII', 'MLMXVIII', 'MLMXIX', 'MLMXX', 'MLMXXI', 'MLMXXII', 'MLMXXIII', 'MLMXXIV', 'MLMXXV', 'MLMXXVI', 'MLMXXVII', 'MLMXXVIII', 'MLMXXIX', 'MLMXXX', 'MLMXXXI', 'MLMXXXII', 'MLMXXXIII', 'MLMXXXIV', 'MLMXXXV', 'MLMXXXVI', 'MLMXXXVII', 'MLMXXXVIII', 'MLMXXXIX', 'MXM', 'MXMI', 'MXMII', 'MXMIII', 'MXMIV', 'MVM', 'MVMI', 'MVMII', 'MVMIII', 'MIM', 'MM', 'MMI', 'MMII', 'MMIII', 'MMIV', 'MMV', 'MMVI', 'MMVII', 'MMVIII', 'MMIX', 'MMX', 'MMXI', 'MMXII', 'MMXIII', 'MMXIV', 'MMXV', 'MMXVI', 'MMXVII', 'MMXVIII', 'MMXIX', 'MMXX', 'MMXXI', 'MMXXII', 'MMXXIII', 'MMXXIV', 'MMXXV', 'MMXXVI', 'MMXXVII', 'MMXXVIII', 'MMXXIX', 'MMXXX', 'MMXXXI', 'MMXXXII', 'MMXXXIII', 'MMXXXIV', 'MMXXXV', 'MMXXXVI', 'MMXXXVII', 'MMXXXVIII', 'MMXXXIX', 'MMXL', 'MMXLI', 'MMXLII', 'MMXLIII', 'MMXLIV', 'MMVL', 'MMVLI', 'MMVLII', 'MMVLIII', 'MMIL', 'MML', 'MMLI', 'MMLII', 'MMLIII', 'MMLIV', 'MMLV', 'MMLVI', 'MMLVII', 'MMLVIII', 'MMLIX', 'MMLX', 'MMLXI', 'MMLXII', 'MMLXIII', 'MMLXIV', 'MMLXV', 'MMLXVI', 'MMLXVII', 'MMLXVIII', 'MMLXIX', 'MMLXX', 'MMLXXI', 'MMLXXII', 'MMLXXIII', 'MMLXXIV', 'MMLXXV', 'MMLXXVI', 'MMLXXVII', 'MMLXXVIII', 'MMLXXIX', 'MMLXXX', 'MMLXXXI', 'MMLXXXII', 'MMLXXXIII', 'MMLXXXIV', 'MMLXXXV', 'MMLXXXVI', 'MMLXXXVII', 'MMLXXXVIII', 'MMLXXXIX', 'MMXC', 'MMXCI', 'MMXCII', 'MMXCIII', 'MMXCIV', 'MMVC', 'MMVCI', 'MMVCII', 'MMVCIII', 'MMIC', 'MMC', 'MMCI', 'MMCII', 'MMCIII', 'MMCIV', 'MMCV', 'MMCVI', 'MMCVII', 'MMCVIII', 'MMCIX', 'MMCX', 'MMCXI', 'MMCXII', 'MMCXIII', 'MMCXIV', 'MMCXV', 'MMCXVI', 'MMCXVII', 'MMCXVIII', 'MMCXIX', 'MMCXX', 'MMCXXI', 'MMCXXII', 'MMCXXIII', 'MMCXXIV', 'MMCXXV', 'MMCXXVI', 'MMCXXVII', 'MMCXXVIII', 'MMCXXIX', 'MMCXXX', 'MMCXXXI', 'MMCXXXII', 'MMCXXXIII', 'MMCXXXIV', 'MMCXXXV', 'MMCXXXVI', 'MMCXXXVII', 'MMCXXXVIII', 'MMCXXXIX', 'MMCXL', 'MMCXLI', 'MMCXLII', 'MMCXLIII', 'MMCXLIV', 'MMCVL', 'MMCVLI', 'MMCVLII', 'MMCVLIII', 'MMCIL', 'MMCL', 'MMCLI', 'MMCLII', 'MMCLIII', 'MMCLIV', 'MMCLV', 'MMCLVI', 'MMCLVII', 'MMCLVIII', 'MMCLIX', 'MMCLX', 'MMCLXI', 'MMCLXII', 'MMCLXIII', 'MMCLXIV', 'MMCLXV', 'MMCLXVI', 'MMCLXVII', 'MMCLXVIII', 'MMCLXIX', 'MMCLXX', 'MMCLXXI', 'MMCLXXII', 'MMCLXXIII', 'MMCLXXIV', 'MMCLXXV', 'MMCLXXVI', 'MMCLXXVII', 'MMCLXXVIII', 'MMCLXXIX', 'MMCLXXX', 'MMCLXXXI', 'MMCLXXXII', 'MMCLXXXIII', 'MMCLXXXIV', 'MMCLXXXV', 'MMCLXXXVI', 'MMCLXXXVII', 'MMCLXXXVIII', 'MMCLXXXIX', 'MMCXC', 'MMCXCI', 'MMCXCII', 'MMCXCIII', 'MMCXCIV', 'MMCVC', 'MMCVCI', 'MMCVCII', 'MMCVCIII', 'MMCIC', 'MMCC', 'MMCCI', 'MMCCII', 'MMCCIII', 'MMCCIV', 'MMCCV', 'MMCCVI', 'MMCCVII', 'MMCCVIII', 'MMCCIX', 'MMCCX', 'MMCCXI', 'MMCCXII', 'MMCCXIII', 'MMCCXIV', 'MMCCXV', 'MMCCXVI', 'MMCCXVII', 'MMCCXVIII', 'MMCCXIX', 'MMCCXX', 'MMCCXXI', 'MMCCXXII', 'MMCCXXIII', 'MMCCXXIV', 'MMCCXXV', 'MMCCXXVI', 'MMCCXXVII', 'MMCCXXVIII', 'MMCCXXIX', 'MMCCXXX', 'MMCCXXXI', 'MMCCXXXII', 'MMCCXXXIII', 'MMCCXXXIV', 'MMCCXXXV', 'MMCCXXXVI', 'MMCCXXXVII', 'MMCCXXXVIII', 'MMCCXXXIX', 'MMCCXL', 'MMCCXLI', 'MMCCXLII', 'MMCCXLIII', 'MMCCXLIV', 'MMCCVL', 'MMCCVLI', 'MMCCVLII', 'MMCCVLIII', 'MMCCIL', 'MMCCL', 'MMCCLI', 'MMCCLII', 'MMCCLIII', 'MMCCLIV', 'MMCCLV', 'MMCCLVI', 'MMCCLVII', 'MMCCLVIII', 'MMCCLIX', 'MMCCLX', 'MMCCLXI', 'MMCCLXII', 'MMCCLXIII', 'MMCCLXIV', 'MMCCLXV', 'MMCCLXVI', 'MMCCLXVII', 'MMCCLXVIII', 'MMCCLXIX', 'MMCCLXX', 'MMCCLXXI', 'MMCCLXXII', 'MMCCLXXIII', 'MMCCLXXIV', 'MMCCLXXV', 'MMCCLXXVI', 'MMCCLXXVII', 'MMCCLXXVIII', 'MMCCLXXIX', 'MMCCLXXX', 'MMCCLXXXI', 'MMCCLXXXII', 'MMCCLXXXIII', 'MMCCLXXXIV', 'MMCCLXXXV', 'MMCCLXXXVI', 'MMCCLXXXVII', 'MMCCLXXXVIII', 'MMCCLXXXIX', 'MMCCXC', 'MMCCXCI', 'MMCCXCII', 'MMCCXCIII', 'MMCCXCIV', 'MMCCVC', 'MMCCVCI', 'MMCCVCII', 'MMCCVCIII', 'MMCCIC', 'MMCCC', 'MMCCCI', 'MMCCCII', 'MMCCCIII', 'MMCCCIV', 'MMCCCV', 'MMCCCVI', 'MMCCCVII', 'MMCCCVIII', 'MMCCCIX', 'MMCCCX', 'MMCCCXI', 'MMCCCXII', 'MMCCCXIII', 'MMCCCXIV', 'MMCCCXV', 'MMCCCXVI', 'MMCCCXVII', 'MMCCCXVIII', 'MMCCCXIX', 'MMCCCXX', 'MMCCCXXI', 'MMCCCXXII', 'MMCCCXXIII', 'MMCCCXXIV', 'MMCCCXXV', 'MMCCCXXVI', 'MMCCCXXVII', 'MMCCCXXVIII', 'MMCCCXXIX', 'MMCCCXXX', 'MMCCCXXXI', 'MMCCCXXXII', 'MMCCCXXXIII', 'MMCCCXXXIV', 'MMCCCXXXV', 'MMCCCXXXVI', 'MMCCCXXXVII', 'MMCCCXXXVIII', 'MMCCCXXXIX', 'MMCCCXL', 'MMCCCXLI', 'MMCCCXLII', 'MMCCCXLIII', 'MMCCCXLIV', 'MMCCCVL', 'MMCCCVLI', 'MMCCCVLII', 'MMCCCVLIII', 'MMCCCIL', 'MMCCCL', 'MMCCCLI', 'MMCCCLII', 'MMCCCLIII', 'MMCCCLIV', 'MMCCCLV', 'MMCCCLVI', 'MMCCCLVII', 'MMCCCLVIII', 'MMCCCLIX', 'MMCCCLX', 'MMCCCLXI', 'MMCCCLXII', 'MMCCCLXIII', 'MMCCCLXIV', 'MMCCCLXV', 'MMCCCLXVI', 'MMCCCLXVII', 'MMCCCLXVIII', 'MMCCCLXIX', 'MMCCCLXX', 'MMCCCLXXI', 'MMCCCLXXII', 'MMCCCLXXIII', 'MMCCCLXXIV', 'MMCCCLXXV', 'MMCCCLXXVI', 'MMCCCLXXVII', 'MMCCCLXXVIII', 'MMCCCLXXIX', 'MMCCCLXXX', 'MMCCCLXXXI', 'MMCCCLXXXII', 'MMCCCLXXXIII', 'MMCCCLXXXIV', 'MMCCCLXXXV', 'MMCCCLXXXVI', 'MMCCCLXXXVII', 'MMCCCLXXXVIII', 'MMCCCLXXXIX', 'MMCCCXC', 'MMCCCXCI', 'MMCCCXCII', 'MMCCCXCIII', 'MMCCCXCIV', 'MMCCCVC', 'MMCCCVCI', 'MMCCCVCII', 'MMCCCVCIII', 'MMCCCIC', 'MMCD', 'MMCDI', 'MMCDII', 'MMCDIII', 'MMCDIV', 'MMCDV', 'MMCDVI', 'MMCDVII', 'MMCDVIII', 'MMCDIX', 'MMCDX', 'MMCDXI', 'MMCDXII', 'MMCDXIII', 'MMCDXIV', 'MMCDXV', 'MMCDXVI', 'MMCDXVII', 'MMCDXVIII', 'MMCDXIX', 'MMCDXX', 'MMCDXXI', 'MMCDXXII', 'MMCDXXIII', 'MMCDXXIV', 'MMCDXXV', 'MMCDXXVI', 'MMCDXXVII', 'MMCDXXVIII', 'MMCDXXIX', 'MMCDXXX', 'MMCDXXXI', 'MMCDXXXII', 'MMCDXXXIII', 'MMCDXXXIV', 'MMCDXXXV', 'MMCDXXXVI', 'MMCDXXXVII', 'MMCDXXXVIII', 'MMCDXXXIX', 'MMCDXL', 'MMCDXLI', 'MMCDXLII', 'MMCDXLIII', 'MMCDXLIV', 'MMCDVL', 'MMCDVLI', 'MMCDVLII', 'MMCDVLIII', 'MMCDIL', 'MMLD', 'MMLDI', 'MMLDII', 'MMLDIII', 'MMLDIV', 'MMLDV', 'MMLDVI', 'MMLDVII', 'MMLDVIII', 'MMLDIX', 'MMLDX', 'MMLDXI', 'MMLDXII', 'MMLDXIII', 'MMLDXIV', 'MMLDXV', 'MMLDXVI', 'MMLDXVII', 'MMLDXVIII', 'MMLDXIX', 'MMLDXX', 'MMLDXXI', 'MMLDXXII', 'MMLDXXIII', 'MMLDXXIV', 'MMLDXXV', 'MMLDXXVI', 'MMLDXXVII', 'MMLDXXVIII', 'MMLDXXIX', 'MMLDXXX', 'MMLDXXXI', 'MMLDXXXII', 'MMLDXXXIII', 'MMLDXXXIV', 'MMLDXXXV', 'MMLDXXXVI', 'MMLDXXXVII', 'MMLDXXXVIII', 'MMLDXXXIX', 'MMXD', 'MMXDI', 'MMXDII', 'MMXDIII', 'MMXDIV', 'MMVD', 'MMVDI', 'MMVDII', 'MMVDIII', 'MMID', 'MMD', 'MMDI', 'MMDII', 'MMDIII', 'MMDIV', 'MMDV', 'MMDVI', 'MMDVII', 'MMDVIII', 'MMDIX', 'MMDX', 'MMDXI', 'MMDXII', 'MMDXIII', 'MMDXIV', 'MMDXV', 'MMDXVI', 'MMDXVII', 'MMDXVIII', 'MMDXIX', 'MMDXX', 'MMDXXI', 'MMDXXII', 'MMDXXIII', 'MMDXXIV', 'MMDXXV', 'MMDXXVI', 'MMDXXVII', 'MMDXXVIII', 'MMDXXIX', 'MMDXXX', 'MMDXXXI', 'MMDXXXII', 'MMDXXXIII', 'MMDXXXIV', 'MMDXXXV', 'MMDXXXVI', 'MMDXXXVII', 'MMDXXXVIII', 'MMDXXXIX', 'MMDXL', 'MMDXLI', 'MMDXLII', 'MMDXLIII', 'MMDXLIV', 'MMDVL', 'MMDVLI', 'MMDVLII', 'MMDVLIII', 'MMDIL', 'MMDL', 'MMDLI', 'MMDLII', 'MMDLIII', 'MMDLIV', 'MMDLV', 'MMDLVI', 'MMDLVII', 'MMDLVIII', 'MMDLIX', 'MMDLX', 'MMDLXI', 'MMDLXII', 'MMDLXIII', 'MMDLXIV', 'MMDLXV', 'MMDLXVI', 'MMDLXVII', 'MMDLXVIII', 'MMDLXIX', 'MMDLXX', 'MMDLXXI', 'MMDLXXII', 'MMDLXXIII', 'MMDLXXIV', 'MMDLXXV', 'MMDLXXVI', 'MMDLXXVII', 'MMDLXXVIII', 'MMDLXXIX', 'MMDLXXX', 'MMDLXXXI', 'MMDLXXXII', 'MMDLXXXIII', 'MMDLXXXIV', 'MMDLXXXV', 'MMDLXXXVI', 'MMDLXXXVII', 'MMDLXXXVIII', 'MMDLXXXIX', 'MMDXC', 'MMDXCI', 'MMDXCII', 'MMDXCIII', 'MMDXCIV', 'MMDVC', 'MMDVCI', 'MMDVCII', 'MMDVCIII', 'MMDIC', 'MMDC', 'MMDCI', 'MMDCII', 'MMDCIII', 'MMDCIV', 'MMDCV', 'MMDCVI', 'MMDCVII', 'MMDCVIII', 'MMDCIX', 'MMDCX', 'MMDCXI', 'MMDCXII', 'MMDCXIII', 'MMDCXIV', 'MMDCXV', 'MMDCXVI', 'MMDCXVII', 'MMDCXVIII', 'MMDCXIX', 'MMDCXX', 'MMDCXXI', 'MMDCXXII', 'MMDCXXIII', 'MMDCXXIV', 'MMDCXXV', 'MMDCXXVI', 'MMDCXXVII', 'MMDCXXVIII', 'MMDCXXIX', 'MMDCXXX', 'MMDCXXXI', 'MMDCXXXII', 'MMDCXXXIII', 'MMDCXXXIV', 'MMDCXXXV', 'MMDCXXXVI', 'MMDCXXXVII', 'MMDCXXXVIII', 'MMDCXXXIX', 'MMDCXL', 'MMDCXLI', 'MMDCXLII', 'MMDCXLIII', 'MMDCXLIV', 'MMDCVL', 'MMDCVLI', 'MMDCVLII', 'MMDCVLIII', 'MMDCIL', 'MMDCL', 'MMDCLI', 'MMDCLII', 'MMDCLIII', 'MMDCLIV', 'MMDCLV', 'MMDCLVI', 'MMDCLVII', 'MMDCLVIII', 'MMDCLIX', 'MMDCLX', 'MMDCLXI', 'MMDCLXII', 'MMDCLXIII', 'MMDCLXIV', 'MMDCLXV', 'MMDCLXVI', 'MMDCLXVII', 'MMDCLXVIII', 'MMDCLXIX', 'MMDCLXX', 'MMDCLXXI', 'MMDCLXXII', 'MMDCLXXIII', 'MMDCLXXIV', 'MMDCLXXV', 'MMDCLXXVI', 'MMDCLXXVII', 'MMDCLXXVIII', 'MMDCLXXIX', 'MMDCLXXX', 'MMDCLXXXI', 'MMDCLXXXII', 'MMDCLXXXIII', 'MMDCLXXXIV', 'MMDCLXXXV', 'MMDCLXXXVI', 'MMDCLXXXVII', 'MMDCLXXXVIII', 'MMDCLXXXIX', 'MMDCXC', 'MMDCXCI', 'MMDCXCII', 'MMDCXCIII', 'MMDCXCIV', 'MMDCVC', 'MMDCVCI', 'MMDCVCII', 'MMDCVCIII', 'MMDCIC', 'MMDCC', 'MMDCCI', 'MMDCCII', 'MMDCCIII', 'MMDCCIV', 'MMDCCV', 'MMDCCVI', 'MMDCCVII', 'MMDCCVIII', 'MMDCCIX', 'MMDCCX', 'MMDCCXI', 'MMDCCXII', 'MMDCCXIII', 'MMDCCXIV', 'MMDCCXV', 'MMDCCXVI', 'MMDCCXVII', 'MMDCCXVIII', 'MMDCCXIX', 'MMDCCXX', 'MMDCCXXI', 'MMDCCXXII', 'MMDCCXXIII', 'MMDCCXXIV', 'MMDCCXXV', 'MMDCCXXVI', 'MMDCCXXVII', 'MMDCCXXVIII', 'MMDCCXXIX', 'MMDCCXXX', 'MMDCCXXXI', 'MMDCCXXXII', 'MMDCCXXXIII', 'MMDCCXXXIV', 'MMDCCXXXV', 'MMDCCXXXVI', 'MMDCCXXXVII', 'MMDCCXXXVIII', 'MMDCCXXXIX', 'MMDCCXL', 'MMDCCXLI', 'MMDCCXLII', 'MMDCCXLIII', 'MMDCCXLIV', 'MMDCCVL', 'MMDCCVLI', 'MMDCCVLII', 'MMDCCVLIII', 'MMDCCIL', 'MMDCCL', 'MMDCCLI', 'MMDCCLII', 'MMDCCLIII', 'MMDCCLIV', 'MMDCCLV', 'MMDCCLVI', 'MMDCCLVII', 'MMDCCLVIII', 'MMDCCLIX', 'MMDCCLX', 'MMDCCLXI', 'MMDCCLXII', 'MMDCCLXIII', 'MMDCCLXIV', 'MMDCCLXV', 'MMDCCLXVI', 'MMDCCLXVII', 'MMDCCLXVIII', 'MMDCCLXIX', 'MMDCCLXX', 'MMDCCLXXI', 'MMDCCLXXII', 'MMDCCLXXIII', 'MMDCCLXXIV', 'MMDCCLXXV', 'MMDCCLXXVI', 'MMDCCLXXVII', 'MMDCCLXXVIII', 'MMDCCLXXIX', 'MMDCCLXXX', 'MMDCCLXXXI', 'MMDCCLXXXII', 'MMDCCLXXXIII', 'MMDCCLXXXIV', 'MMDCCLXXXV', 'MMDCCLXXXVI', 'MMDCCLXXXVII', 'MMDCCLXXXVIII', 'MMDCCLXXXIX', 'MMDCCXC', 'MMDCCXCI', 'MMDCCXCII', 'MMDCCXCIII', 'MMDCCXCIV', 'MMDCCVC', 'MMDCCVCI', 'MMDCCVCII', 'MMDCCVCIII', 'MMDCCIC', 'MMDCCC', 'MMDCCCI', 'MMDCCCII', 'MMDCCCIII', 'MMDCCCIV', 'MMDCCCV', 'MMDCCCVI', 'MMDCCCVII', 'MMDCCCVIII', 'MMDCCCIX', 'MMDCCCX', 'MMDCCCXI', 'MMDCCCXII', 'MMDCCCXIII', 'MMDCCCXIV', 'MMDCCCXV', 'MMDCCCXVI', 'MMDCCCXVII', 'MMDCCCXVIII', 'MMDCCCXIX', 'MMDCCCXX', 'MMDCCCXXI', 'MMDCCCXXII', 'MMDCCCXXIII', 'MMDCCCXXIV', 'MMDCCCXXV', 'MMDCCCXXVI', 'MMDCCCXXVII', 'MMDCCCXXVIII', 'MMDCCCXXIX', 'MMDCCCXXX', 'MMDCCCXXXI', 'MMDCCCXXXII', 'MMDCCCXXXIII', 'MMDCCCXXXIV', 'MMDCCCXXXV', 'MMDCCCXXXVI', 'MMDCCCXXXVII', 'MMDCCCXXXVIII', 'MMDCCCXXXIX', 'MMDCCCXL', 'MMDCCCXLI', 'MMDCCCXLII', 'MMDCCCXLIII', 'MMDCCCXLIV', 'MMDCCCVL', 'MMDCCCVLI', 'MMDCCCVLII', 'MMDCCCVLIII', 'MMDCCCIL', 'MMDCCCL', 'MMDCCCLI', 'MMDCCCLII', 'MMDCCCLIII', 'MMDCCCLIV', 'MMDCCCLV', 'MMDCCCLVI', 'MMDCCCLVII', 'MMDCCCLVIII', 'MMDCCCLIX', 'MMDCCCLX', 'MMDCCCLXI', 'MMDCCCLXII', 'MMDCCCLXIII', 'MMDCCCLXIV', 'MMDCCCLXV', 'MMDCCCLXVI', 'MMDCCCLXVII', 'MMDCCCLXVIII', 'MMDCCCLXIX', 'MMDCCCLXX', 'MMDCCCLXXI', 'MMDCCCLXXII', 'MMDCCCLXXIII', 'MMDCCCLXXIV', 'MMDCCCLXXV', 'MMDCCCLXXVI', 'MMDCCCLXXVII', 'MMDCCCLXXVIII', 'MMDCCCLXXIX', 'MMDCCCLXXX', 'MMDCCCLXXXI', 'MMDCCCLXXXII', 'MMDCCCLXXXIII', 'MMDCCCLXXXIV', 'MMDCCCLXXXV', 'MMDCCCLXXXVI', 'MMDCCCLXXXVII', 'MMDCCCLXXXVIII', 'MMDCCCLXXXIX', 'MMDCCCXC', 'MMDCCCXCI', 'MMDCCCXCII', 'MMDCCCXCIII', 'MMDCCCXCIV', 'MMDCCCVC', 'MMDCCCVCI', 'MMDCCCVCII', 'MMDCCCVCIII', 'MMDCCCIC', 'MMCM', 'MMCMI', 'MMCMII', 'MMCMIII', 'MMCMIV', 'MMCMV', 'MMCMVI', 'MMCMVII', 'MMCMVIII', 'MMCMIX', 'MMCMX', 'MMCMXI', 'MMCMXII', 'MMCMXIII', 'MMCMXIV', 'MMCMXV', 'MMCMXVI', 'MMCMXVII', 'MMCMXVIII', 'MMCMXIX', 'MMCMXX', 'MMCMXXI', 'MMCMXXII', 'MMCMXXIII', 'MMCMXXIV', 'MMCMXXV', 'MMCMXXVI', 'MMCMXXVII', 'MMCMXXVIII', 'MMCMXXIX', 'MMCMXXX', 'MMCMXXXI', 'MMCMXXXII', 'MMCMXXXIII', 'MMCMXXXIV', 'MMCMXXXV', 'MMCMXXXVI', 'MMCMXXXVII', 'MMCMXXXVIII', 'MMCMXXXIX', 'MMCMXL', 'MMCMXLI', 'MMCMXLII', 'MMCMXLIII', 'MMCMXLIV', 'MMCMVL', 'MMCMVLI', 'MMCMVLII', 'MMCMVLIII', 'MMCMIL', 'MMLM', 'MMLMI', 'MMLMII', 'MMLMIII', 'MMLMIV', 'MMLMV', 'MMLMVI', 'MMLMVII', 'MMLMVIII', 'MMLMIX', 'MMLMX', 'MMLMXI', 'MMLMXII', 'MMLMXIII', 'MMLMXIV', 'MMLMXV', 'MMLMXVI', 'MMLMXVII', 'MMLMXVIII', 'MMLMXIX', 'MMLMXX', 'MMLMXXI', 'MMLMXXII', 'MMLMXXIII', 'MMLMXXIV', 'MMLMXXV', 'MMLMXXVI', 'MMLMXXVII', 'MMLMXXVIII', 'MMLMXXIX', 'MMLMXXX', 'MMLMXXXI', 'MMLMXXXII', 'MMLMXXXIII', 'MMLMXXXIV', 'MMLMXXXV', 'MMLMXXXVI', 'MMLMXXXVII', 'MMLMXXXVIII', 'MMLMXXXIX', 'MMXM', 'MMXMI', 'MMXMII', 'MMXMIII', 'MMXMIV', 'MMVM', 'MMVMI', 'MMVMII', 'MMVMIII', 'MMIM', 'MMM', 'MMMI', 'MMMII', 'MMMIII', 'MMMIV', 'MMMV', 'MMMVI', 'MMMVII', 'MMMVIII', 'MMMIX', 'MMMX', 'MMMXI', 'MMMXII', 'MMMXIII', 'MMMXIV', 'MMMXV', 'MMMXVI', 'MMMXVII', 'MMMXVIII', 'MMMXIX', 'MMMXX', 'MMMXXI', 'MMMXXII', 'MMMXXIII', 'MMMXXIV', 'MMMXXV', 'MMMXXVI', 'MMMXXVII', 'MMMXXVIII', 'MMMXXIX', 'MMMXXX', 'MMMXXXI', 'MMMXXXII', 'MMMXXXIII', 'MMMXXXIV', 'MMMXXXV', 'MMMXXXVI', 'MMMXXXVII', 'MMMXXXVIII', 'MMMXXXIX', 'MMMXL', 'MMMXLI', 'MMMXLII', 'MMMXLIII', 'MMMXLIV', 'MMMVL', 'MMMVLI', 'MMMVLII', 'MMMVLIII', 'MMMIL', 'MMML', 'MMMLI', 'MMMLII', 'MMMLIII', 'MMMLIV', 'MMMLV', 'MMMLVI', 'MMMLVII', 'MMMLVIII', 'MMMLIX', 'MMMLX', 'MMMLXI', 'MMMLXII', 'MMMLXIII', 'MMMLXIV', 'MMMLXV', 'MMMLXVI', 'MMMLXVII', 'MMMLXVIII', 'MMMLXIX', 'MMMLXX', 'MMMLXXI', 'MMMLXXII', 'MMMLXXIII', 'MMMLXXIV', 'MMMLXXV', 'MMMLXXVI', 'MMMLXXVII', 'MMMLXXVIII', 'MMMLXXIX', 'MMMLXXX', 'MMMLXXXI', 'MMMLXXXII', 'MMMLXXXIII', 'MMMLXXXIV', 'MMMLXXXV', 'MMMLXXXVI', 'MMMLXXXVII', 'MMMLXXXVIII', 'MMMLXXXIX', 'MMMXC', 'MMMXCI', 'MMMXCII', 'MMMXCIII', 'MMMXCIV', 'MMMVC', 'MMMVCI', 'MMMVCII', 'MMMVCIII', 'MMMIC', 'MMMC', 'MMMCI', 'MMMCII', 'MMMCIII', 'MMMCIV', 'MMMCV', 'MMMCVI', 'MMMCVII', 'MMMCVIII', 'MMMCIX', 'MMMCX', 'MMMCXI', 'MMMCXII', 'MMMCXIII', 'MMMCXIV', 'MMMCXV', 'MMMCXVI', 'MMMCXVII', 'MMMCXVIII', 'MMMCXIX', 'MMMCXX', 'MMMCXXI', 'MMMCXXII', 'MMMCXXIII', 'MMMCXXIV', 'MMMCXXV', 'MMMCXXVI', 'MMMCXXVII', 'MMMCXXVIII', 'MMMCXXIX', 'MMMCXXX', 'MMMCXXXI', 'MMMCXXXII', 'MMMCXXXIII', 'MMMCXXXIV', 'MMMCXXXV', 'MMMCXXXVI', 'MMMCXXXVII', 'MMMCXXXVIII', 'MMMCXXXIX', 'MMMCXL', 'MMMCXLI', 'MMMCXLII', 'MMMCXLIII', 'MMMCXLIV', 'MMMCVL', 'MMMCVLI', 'MMMCVLII', 'MMMCVLIII', 'MMMCIL', 'MMMCL', 'MMMCLI', 'MMMCLII', 'MMMCLIII', 'MMMCLIV', 'MMMCLV', 'MMMCLVI', 'MMMCLVII', 'MMMCLVIII', 'MMMCLIX', 'MMMCLX', 'MMMCLXI', 'MMMCLXII', 'MMMCLXIII', 'MMMCLXIV', 'MMMCLXV', 'MMMCLXVI', 'MMMCLXVII', 'MMMCLXVIII', 'MMMCLXIX', 'MMMCLXX', 'MMMCLXXI', 'MMMCLXXII', 'MMMCLXXIII', 'MMMCLXXIV', 'MMMCLXXV', 'MMMCLXXVI', 'MMMCLXXVII', 'MMMCLXXVIII', 'MMMCLXXIX', 'MMMCLXXX', 'MMMCLXXXI', 'MMMCLXXXII', 'MMMCLXXXIII', 'MMMCLXXXIV', 'MMMCLXXXV', 'MMMCLXXXVI', 'MMMCLXXXVII', 'MMMCLXXXVIII', 'MMMCLXXXIX', 'MMMCXC', 'MMMCXCI', 'MMMCXCII', 'MMMCXCIII', 'MMMCXCIV', 'MMMCVC', 'MMMCVCI', 'MMMCVCII', 'MMMCVCIII', 'MMMCIC', 'MMMCC', 'MMMCCI', 'MMMCCII', 'MMMCCIII', 'MMMCCIV', 'MMMCCV', 'MMMCCVI', 'MMMCCVII', 'MMMCCVIII', 'MMMCCIX', 'MMMCCX', 'MMMCCXI', 'MMMCCXII', 'MMMCCXIII', 'MMMCCXIV', 'MMMCCXV', 'MMMCCXVI', 'MMMCCXVII', 'MMMCCXVIII', 'MMMCCXIX', 'MMMCCXX', 'MMMCCXXI', 'MMMCCXXII', 'MMMCCXXIII', 'MMMCCXXIV', 'MMMCCXXV', 'MMMCCXXVI', 'MMMCCXXVII', 'MMMCCXXVIII', 'MMMCCXXIX', 'MMMCCXXX', 'MMMCCXXXI', 'MMMCCXXXII', 'MMMCCXXXIII', 'MMMCCXXXIV', 'MMMCCXXXV', 'MMMCCXXXVI', 'MMMCCXXXVII', 'MMMCCXXXVIII', 'MMMCCXXXIX', 'MMMCCXL', 'MMMCCXLI', 'MMMCCXLII', 'MMMCCXLIII', 'MMMCCXLIV', 'MMMCCVL', 'MMMCCVLI', 'MMMCCVLII', 'MMMCCVLIII', 'MMMCCIL', 'MMMCCL', 'MMMCCLI', 'MMMCCLII', 'MMMCCLIII', 'MMMCCLIV', 'MMMCCLV', 'MMMCCLVI', 'MMMCCLVII', 'MMMCCLVIII', 'MMMCCLIX', 'MMMCCLX', 'MMMCCLXI', 'MMMCCLXII', 'MMMCCLXIII', 'MMMCCLXIV', 'MMMCCLXV', 'MMMCCLXVI', 'MMMCCLXVII', 'MMMCCLXVIII', 'MMMCCLXIX', 'MMMCCLXX', 'MMMCCLXXI', 'MMMCCLXXII', 'MMMCCLXXIII', 'MMMCCLXXIV', 'MMMCCLXXV', 'MMMCCLXXVI', 'MMMCCLXXVII', 'MMMCCLXXVIII', 'MMMCCLXXIX', 'MMMCCLXXX', 'MMMCCLXXXI', 'MMMCCLXXXII', 'MMMCCLXXXIII', 'MMMCCLXXXIV', 'MMMCCLXXXV', 'MMMCCLXXXVI', 'MMMCCLXXXVII', 'MMMCCLXXXVIII', 'MMMCCLXXXIX', 'MMMCCXC', 'MMMCCXCI', 'MMMCCXCII', 'MMMCCXCIII', 'MMMCCXCIV', 'MMMCCVC', 'MMMCCVCI', 'MMMCCVCII', 'MMMCCVCIII', 'MMMCCIC', 'MMMCCC', 'MMMCCCI', 'MMMCCCII', 'MMMCCCIII', 'MMMCCCIV', 'MMMCCCV', 'MMMCCCVI', 'MMMCCCVII', 'MMMCCCVIII', 'MMMCCCIX', 'MMMCCCX', 'MMMCCCXI', 'MMMCCCXII', 'MMMCCCXIII', 'MMMCCCXIV', 'MMMCCCXV', 'MMMCCCXVI', 'MMMCCCXVII', 'MMMCCCXVIII', 'MMMCCCXIX', 'MMMCCCXX', 'MMMCCCXXI', 'MMMCCCXXII', 'MMMCCCXXIII', 'MMMCCCXXIV', 'MMMCCCXXV', 'MMMCCCXXVI', 'MMMCCCXXVII', 'MMMCCCXXVIII', 'MMMCCCXXIX', 'MMMCCCXXX', 'MMMCCCXXXI', 'MMMCCCXXXII', 'MMMCCCXXXIII', 'MMMCCCXXXIV', 'MMMCCCXXXV', 'MMMCCCXXXVI', 'MMMCCCXXXVII', 'MMMCCCXXXVIII', 'MMMCCCXXXIX', 'MMMCCCXL', 'MMMCCCXLI', 'MMMCCCXLII', 'MMMCCCXLIII', 'MMMCCCXLIV', 'MMMCCCVL', 'MMMCCCVLI', 'MMMCCCVLII', 'MMMCCCVLIII', 'MMMCCCIL', 'MMMCCCL', 'MMMCCCLI', 'MMMCCCLII', 'MMMCCCLIII', 'MMMCCCLIV', 'MMMCCCLV', 'MMMCCCLVI', 'MMMCCCLVII', 'MMMCCCLVIII', 'MMMCCCLIX', 'MMMCCCLX', 'MMMCCCLXI', 'MMMCCCLXII', 'MMMCCCLXIII', 'MMMCCCLXIV', 'MMMCCCLXV', 'MMMCCCLXVI', 'MMMCCCLXVII', 'MMMCCCLXVIII', 'MMMCCCLXIX', 'MMMCCCLXX', 'MMMCCCLXXI', 'MMMCCCLXXII', 'MMMCCCLXXIII', 'MMMCCCLXXIV', 'MMMCCCLXXV', 'MMMCCCLXXVI', 'MMMCCCLXXVII', 'MMMCCCLXXVIII', 'MMMCCCLXXIX', 'MMMCCCLXXX', 'MMMCCCLXXXI', 'MMMCCCLXXXII', 'MMMCCCLXXXIII', 'MMMCCCLXXXIV', 'MMMCCCLXXXV', 'MMMCCCLXXXVI', 'MMMCCCLXXXVII', 'MMMCCCLXXXVIII', 'MMMCCCLXXXIX', 'MMMCCCXC', 'MMMCCCXCI', 'MMMCCCXCII', 'MMMCCCXCIII', 'MMMCCCXCIV', 'MMMCCCVC', 'MMMCCCVCI', 'MMMCCCVCII', 'MMMCCCVCIII', 'MMMCCCIC', 'MMMCD', 'MMMCDI', 'MMMCDII', 'MMMCDIII', 'MMMCDIV', 'MMMCDV', 'MMMCDVI', 'MMMCDVII', 'MMMCDVIII', 'MMMCDIX', 'MMMCDX', 'MMMCDXI', 'MMMCDXII', 'MMMCDXIII', 'MMMCDXIV', 'MMMCDXV', 'MMMCDXVI', 'MMMCDXVII', 'MMMCDXVIII', 'MMMCDXIX', 'MMMCDXX', 'MMMCDXXI', 'MMMCDXXII', 'MMMCDXXIII', 'MMMCDXXIV', 'MMMCDXXV', 'MMMCDXXVI', 'MMMCDXXVII', 'MMMCDXXVIII', 'MMMCDXXIX', 'MMMCDXXX', 'MMMCDXXXI', 'MMMCDXXXII', 'MMMCDXXXIII', 'MMMCDXXXIV', 'MMMCDXXXV', 'MMMCDXXXVI', 'MMMCDXXXVII', 'MMMCDXXXVIII', 'MMMCDXXXIX', 'MMMCDXL', 'MMMCDXLI', 'MMMCDXLII', 'MMMCDXLIII', 'MMMCDXLIV', 'MMMCDVL', 'MMMCDVLI', 'MMMCDVLII', 'MMMCDVLIII', 'MMMCDIL', 'MMMLD', 'MMMLDI', 'MMMLDII', 'MMMLDIII', 'MMMLDIV', 'MMMLDV', 'MMMLDVI', 'MMMLDVII', 'MMMLDVIII', 'MMMLDIX', 'MMMLDX', 'MMMLDXI', 'MMMLDXII', 'MMMLDXIII', 'MMMLDXIV', 'MMMLDXV', 'MMMLDXVI', 'MMMLDXVII', 'MMMLDXVIII', 'MMMLDXIX', 'MMMLDXX', 'MMMLDXXI', 'MMMLDXXII', 'MMMLDXXIII', 'MMMLDXXIV', 'MMMLDXXV', 'MMMLDXXVI', 'MMMLDXXVII', 'MMMLDXXVIII', 'MMMLDXXIX', 'MMMLDXXX', 'MMMLDXXXI', 'MMMLDXXXII', 'MMMLDXXXIII', 'MMMLDXXXIV', 'MMMLDXXXV', 'MMMLDXXXVI', 'MMMLDXXXVII', 'MMMLDXXXVIII', 'MMMLDXXXIX', 'MMMXD', 'MMMXDI', 'MMMXDII', 'MMMXDIII', 'MMMXDIV', 'MMMVD', 'MMMVDI', 'MMMVDII', 'MMMVDIII', 'MMMID', 'MMMD', 'MMMDI', 'MMMDII', 'MMMDIII', 'MMMDIV', 'MMMDV', 'MMMDVI', 'MMMDVII', 'MMMDVIII', 'MMMDIX', 'MMMDX', 'MMMDXI', 'MMMDXII', 'MMMDXIII', 'MMMDXIV', 'MMMDXV', 'MMMDXVI', 'MMMDXVII', 'MMMDXVIII', 'MMMDXIX', 'MMMDXX', 'MMMDXXI', 'MMMDXXII', 'MMMDXXIII', 'MMMDXXIV', 'MMMDXXV', 'MMMDXXVI', 'MMMDXXVII', 'MMMDXXVIII', 'MMMDXXIX', 'MMMDXXX', 'MMMDXXXI', 'MMMDXXXII', 'MMMDXXXIII', 'MMMDXXXIV', 'MMMDXXXV', 'MMMDXXXVI', 'MMMDXXXVII', 'MMMDXXXVIII', 'MMMDXXXIX', 'MMMDXL', 'MMMDXLI', 'MMMDXLII', 'MMMDXLIII', 'MMMDXLIV', 'MMMDVL', 'MMMDVLI', 'MMMDVLII', 'MMMDVLIII', 'MMMDIL', 'MMMDL', 'MMMDLI', 'MMMDLII', 'MMMDLIII', 'MMMDLIV', 'MMMDLV', 'MMMDLVI', 'MMMDLVII', 'MMMDLVIII', 'MMMDLIX', 'MMMDLX', 'MMMDLXI', 'MMMDLXII', 'MMMDLXIII', 'MMMDLXIV', 'MMMDLXV', 'MMMDLXVI', 'MMMDLXVII', 'MMMDLXVIII', 'MMMDLXIX', 'MMMDLXX', 'MMMDLXXI', 'MMMDLXXII', 'MMMDLXXIII', 'MMMDLXXIV', 'MMMDLXXV', 'MMMDLXXVI', 'MMMDLXXVII', 'MMMDLXXVIII', 'MMMDLXXIX', 'MMMDLXXX', 'MMMDLXXXI', 'MMMDLXXXII', 'MMMDLXXXIII', 'MMMDLXXXIV', 'MMMDLXXXV', 'MMMDLXXXVI', 'MMMDLXXXVII', 'MMMDLXXXVIII', 'MMMDLXXXIX', 'MMMDXC', 'MMMDXCI', 'MMMDXCII', 'MMMDXCIII', 'MMMDXCIV', 'MMMDVC', 'MMMDVCI', 'MMMDVCII', 'MMMDVCIII', 'MMMDIC', 'MMMDC', 'MMMDCI', 'MMMDCII', 'MMMDCIII', 'MMMDCIV', 'MMMDCV', 'MMMDCVI', 'MMMDCVII', 'MMMDCVIII', 'MMMDCIX', 'MMMDCX', 'MMMDCXI', 'MMMDCXII', 'MMMDCXIII', 'MMMDCXIV', 'MMMDCXV', 'MMMDCXVI', 'MMMDCXVII', 'MMMDCXVIII', 'MMMDCXIX', 'MMMDCXX', 'MMMDCXXI', 'MMMDCXXII', 'MMMDCXXIII', 'MMMDCXXIV', 'MMMDCXXV', 'MMMDCXXVI', 'MMMDCXXVII', 'MMMDCXXVIII', 'MMMDCXXIX', 'MMMDCXXX', 'MMMDCXXXI', 'MMMDCXXXII', 'MMMDCXXXIII', 'MMMDCXXXIV', 'MMMDCXXXV', 'MMMDCXXXVI', 'MMMDCXXXVII', 'MMMDCXXXVIII', 'MMMDCXXXIX', 'MMMDCXL', 'MMMDCXLI', 'MMMDCXLII', 'MMMDCXLIII', 'MMMDCXLIV', 'MMMDCVL', 'MMMDCVLI', 'MMMDCVLII', 'MMMDCVLIII', 'MMMDCIL', 'MMMDCL', 'MMMDCLI', 'MMMDCLII', 'MMMDCLIII', 'MMMDCLIV', 'MMMDCLV', 'MMMDCLVI', 'MMMDCLVII', 'MMMDCLVIII', 'MMMDCLIX', 'MMMDCLX', 'MMMDCLXI', 'MMMDCLXII', 'MMMDCLXIII', 'MMMDCLXIV', 'MMMDCLXV', 'MMMDCLXVI', 'MMMDCLXVII', 'MMMDCLXVIII', 'MMMDCLXIX', 'MMMDCLXX', 'MMMDCLXXI', 'MMMDCLXXII', 'MMMDCLXXIII', 'MMMDCLXXIV', 'MMMDCLXXV', 'MMMDCLXXVI', 'MMMDCLXXVII', 'MMMDCLXXVIII', 'MMMDCLXXIX', 'MMMDCLXXX', 'MMMDCLXXXI', 'MMMDCLXXXII', 'MMMDCLXXXIII', 'MMMDCLXXXIV', 'MMMDCLXXXV', 'MMMDCLXXXVI', 'MMMDCLXXXVII', 'MMMDCLXXXVIII', 'MMMDCLXXXIX', 'MMMDCXC', 'MMMDCXCI', 'MMMDCXCII', 'MMMDCXCIII', 'MMMDCXCIV', 'MMMDCVC', 'MMMDCVCI', 'MMMDCVCII', 'MMMDCVCIII', 'MMMDCIC', 'MMMDCC', 'MMMDCCI', 'MMMDCCII', 'MMMDCCIII', 'MMMDCCIV', 'MMMDCCV', 'MMMDCCVI', 'MMMDCCVII', 'MMMDCCVIII', 'MMMDCCIX', 'MMMDCCX', 'MMMDCCXI', 'MMMDCCXII', 'MMMDCCXIII', 'MMMDCCXIV', 'MMMDCCXV', 'MMMDCCXVI', 'MMMDCCXVII', 'MMMDCCXVIII', 'MMMDCCXIX', 'MMMDCCXX', 'MMMDCCXXI', 'MMMDCCXXII', 'MMMDCCXXIII', 'MMMDCCXXIV', 'MMMDCCXXV', 'MMMDCCXXVI', 'MMMDCCXXVII', 'MMMDCCXXVIII', 'MMMDCCXXIX', 'MMMDCCXXX', 'MMMDCCXXXI', 'MMMDCCXXXII', 'MMMDCCXXXIII', 'MMMDCCXXXIV', 'MMMDCCXXXV', 'MMMDCCXXXVI', 'MMMDCCXXXVII', 'MMMDCCXXXVIII', 'MMMDCCXXXIX', 'MMMDCCXL', 'MMMDCCXLI', 'MMMDCCXLII', 'MMMDCCXLIII', 'MMMDCCXLIV', 'MMMDCCVL', 'MMMDCCVLI', 'MMMDCCVLII', 'MMMDCCVLIII', 'MMMDCCIL', 'MMMDCCL', 'MMMDCCLI', 'MMMDCCLII', 'MMMDCCLIII', 'MMMDCCLIV', 'MMMDCCLV', 'MMMDCCLVI', 'MMMDCCLVII', 'MMMDCCLVIII', 'MMMDCCLIX', 'MMMDCCLX', 'MMMDCCLXI', 'MMMDCCLXII', 'MMMDCCLXIII', 'MMMDCCLXIV', 'MMMDCCLXV', 'MMMDCCLXVI', 'MMMDCCLXVII', 'MMMDCCLXVIII', 'MMMDCCLXIX', 'MMMDCCLXX', 'MMMDCCLXXI', 'MMMDCCLXXII', 'MMMDCCLXXIII', 'MMMDCCLXXIV', 'MMMDCCLXXV', 'MMMDCCLXXVI', 'MMMDCCLXXVII', 'MMMDCCLXXVIII', 'MMMDCCLXXIX', 'MMMDCCLXXX', 'MMMDCCLXXXI', 'MMMDCCLXXXII', 'MMMDCCLXXXIII', 'MMMDCCLXXXIV', 'MMMDCCLXXXV', 'MMMDCCLXXXVI', 'MMMDCCLXXXVII', 'MMMDCCLXXXVIII', 'MMMDCCLXXXIX', 'MMMDCCXC', 'MMMDCCXCI', 'MMMDCCXCII', 'MMMDCCXCIII', 'MMMDCCXCIV', 'MMMDCCVC', 'MMMDCCVCI', 'MMMDCCVCII', 'MMMDCCVCIII', 'MMMDCCIC', 'MMMDCCC', 'MMMDCCCI', 'MMMDCCCII', 'MMMDCCCIII', 'MMMDCCCIV', 'MMMDCCCV', 'MMMDCCCVI', 'MMMDCCCVII', 'MMMDCCCVIII', 'MMMDCCCIX', 'MMMDCCCX', 'MMMDCCCXI', 'MMMDCCCXII', 'MMMDCCCXIII', 'MMMDCCCXIV', 'MMMDCCCXV', 'MMMDCCCXVI', 'MMMDCCCXVII', 'MMMDCCCXVIII', 'MMMDCCCXIX', 'MMMDCCCXX', 'MMMDCCCXXI', 'MMMDCCCXXII', 'MMMDCCCXXIII', 'MMMDCCCXXIV', 'MMMDCCCXXV', 'MMMDCCCXXVI', 'MMMDCCCXXVII', 'MMMDCCCXXVIII', 'MMMDCCCXXIX', 'MMMDCCCXXX', 'MMMDCCCXXXI', 'MMMDCCCXXXII', 'MMMDCCCXXXIII', 'MMMDCCCXXXIV', 'MMMDCCCXXXV', 'MMMDCCCXXXVI', 'MMMDCCCXXXVII', 'MMMDCCCXXXVIII', 'MMMDCCCXXXIX', 'MMMDCCCXL', 'MMMDCCCXLI', 'MMMDCCCXLII', 'MMMDCCCXLIII', 'MMMDCCCXLIV', 'MMMDCCCVL', 'MMMDCCCVLI', 'MMMDCCCVLII', 'MMMDCCCVLIII', 'MMMDCCCIL', 'MMMDCCCL', 'MMMDCCCLI', 'MMMDCCCLII', 'MMMDCCCLIII', 'MMMDCCCLIV', 'MMMDCCCLV', 'MMMDCCCLVI', 'MMMDCCCLVII', 'MMMDCCCLVIII', 'MMMDCCCLIX', 'MMMDCCCLX', 'MMMDCCCLXI', 'MMMDCCCLXII', 'MMMDCCCLXIII', 'MMMDCCCLXIV', 'MMMDCCCLXV', 'MMMDCCCLXVI', 'MMMDCCCLXVII', 'MMMDCCCLXVIII', 'MMMDCCCLXIX', 'MMMDCCCLXX', 'MMMDCCCLXXI', 'MMMDCCCLXXII', 'MMMDCCCLXXIII', 'MMMDCCCLXXIV', 'MMMDCCCLXXV', 'MMMDCCCLXXVI', 'MMMDCCCLXXVII', 'MMMDCCCLXXVIII', 'MMMDCCCLXXIX', 'MMMDCCCLXXX', 'MMMDCCCLXXXI', 'MMMDCCCLXXXII', 'MMMDCCCLXXXIII', 'MMMDCCCLXXXIV', 'MMMDCCCLXXXV', 'MMMDCCCLXXXVI', 'MMMDCCCLXXXVII', 'MMMDCCCLXXXVIII', 'MMMDCCCLXXXIX', 'MMMDCCCXC', 'MMMDCCCXCI', 'MMMDCCCXCII', 'MMMDCCCXCIII', 'MMMDCCCXCIV', 'MMMDCCCVC', 'MMMDCCCVCI', 'MMMDCCCVCII', 'MMMDCCCVCIII', 'MMMDCCCIC', 'MMMCM', 'MMMCMI', 'MMMCMII', 'MMMCMIII', 'MMMCMIV', 'MMMCMV', 'MMMCMVI', 'MMMCMVII', 'MMMCMVIII', 'MMMCMIX', 'MMMCMX', 'MMMCMXI', 'MMMCMXII', 'MMMCMXIII', 'MMMCMXIV', 'MMMCMXV', 'MMMCMXVI', 'MMMCMXVII', 'MMMCMXVIII', 'MMMCMXIX', 'MMMCMXX', 'MMMCMXXI', 'MMMCMXXII', 'MMMCMXXIII', 'MMMCMXXIV', 'MMMCMXXV', 'MMMCMXXVI', 'MMMCMXXVII', 'MMMCMXXVIII', 'MMMCMXXIX', 'MMMCMXXX', 'MMMCMXXXI', 'MMMCMXXXII', 'MMMCMXXXIII', 'MMMCMXXXIV', 'MMMCMXXXV', 'MMMCMXXXVI', 'MMMCMXXXVII', 'MMMCMXXXVIII', 'MMMCMXXXIX', 'MMMCMXL', 'MMMCMXLI', 'MMMCMXLII', 'MMMCMXLIII', 'MMMCMXLIV', 'MMMCMVL', 'MMMCMVLI', 'MMMCMVLII', 'MMMCMVLIII', 'MMMCMIL', 'MMMLM', 'MMMLMI', 'MMMLMII', 'MMMLMIII', 'MMMLMIV', 'MMMLMV', 'MMMLMVI', 'MMMLMVII', 'MMMLMVIII', 'MMMLMIX', 'MMMLMX', 'MMMLMXI', 'MMMLMXII', 'MMMLMXIII', 'MMMLMXIV', 'MMMLMXV', 'MMMLMXVI', 'MMMLMXVII', 'MMMLMXVIII', 'MMMLMXIX', 'MMMLMXX', 'MMMLMXXI', 'MMMLMXXII', 'MMMLMXXIII', 'MMMLMXXIV', 'MMMLMXXV', 'MMMLMXXVI', 'MMMLMXXVII', 'MMMLMXXVIII', 'MMMLMXXIX', 'MMMLMXXX', 'MMMLMXXXI', 'MMMLMXXXII', 'MMMLMXXXIII', 'MMMLMXXXIV', 'MMMLMXXXV', 'MMMLMXXXVI', 'MMMLMXXXVII', 'MMMLMXXXVIII', 'MMMLMXXXIX', 'MMMXM', 'MMMXMI', 'MMMXMII', 'MMMXMIII', 'MMMXMIV', 'MMMVM', 'MMMVMI', 'MMMVMII', 'MMMVMIII', 'MMMIM', ] diff --git a/test/unit/interpreter/function-round.spec.ts b/test/unit/interpreter/function-round.spec.ts deleted file mode 100644 index a3070155f7..0000000000 --- a/test/unit/interpreter/function-round.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ROUND', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUND()', '=ROUND(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUND(1.3)', '=ROUND(1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(2) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUND(-1.3)', '=ROUND(-1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-1) - expect(engine.getCellValue(adr('B1'))).toBe(-2) - }) - - it('no -0', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUND(-0.001)', '=ROUND(0.001)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBe(0) - }) - - it('works with positive rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUND(1.43, 1)', '=ROUND(1.47, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1.4) - expect(engine.getCellValue(adr('B1'))).toBe(1.5) - }) - - it('works with negative rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUND(43, -1)', '=ROUND(47, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(40) - expect(engine.getCellValue(adr('B1'))).toBe(50) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUND("42.3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(42) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=ROUND(A1)', '=ROUND(42, A1)', '=ROUND(A1, FOO())'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-rounddown.spec.ts b/test/unit/interpreter/function-rounddown.spec.ts deleted file mode 100644 index f4070d4681..0000000000 --- a/test/unit/interpreter/function-rounddown.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ROUNDDOWN', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDDOWN()', '=ROUNDDOWN(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDDOWN(1.3)', '=ROUNDDOWN(1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(1) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDDOWN(-1.3)', '=ROUNDDOWN(-1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-1) - expect(engine.getCellValue(adr('B1'))).toBe(-1) - }) - - it('works with positive rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDDOWN(1.43, 1)', '=ROUNDDOWN(1.47, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1.4) - expect(engine.getCellValue(adr('B1'))).toBe(1.4) - }) - - it('works with negative rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDDOWN(43, -1)', '=ROUNDDOWN(47, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(40) - expect(engine.getCellValue(adr('B1'))).toBe(40) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDDOWN("42.3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(42) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=ROUNDDOWN(A1)', '=ROUNDDOWN(42, A1)', '=ROUNDDOWN(A1, FOO())'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-roundup.spec.ts b/test/unit/interpreter/function-roundup.spec.ts deleted file mode 100644 index 92569e54dd..0000000000 --- a/test/unit/interpreter/function-roundup.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ROUNDUP', () => { - it('number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDUP()', '=ROUNDUP(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for positive numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDUP(1.3)', '=ROUNDUP(1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(2) - expect(engine.getCellValue(adr('B1'))).toBe(2) - }) - - it('works for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDUP(-1.3)', '=ROUNDUP(-1.7)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-2) - expect(engine.getCellValue(adr('B1'))).toBe(-2) - }) - - it('works with positive rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDUP(1.43, 1)', '=ROUNDUP(1.47, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(1.5) - expect(engine.getCellValue(adr('B1'))).toBe(1.5) - }) - - it('works with negative rounding argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDUP(43, -1)', '=ROUNDUP(47, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(50) - expect(engine.getCellValue(adr('B1'))).toBe(50) - }) - - it('use coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROUNDUP("42.3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(43) - }) - - it('propagates error', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=ROUNDUP(A1)', '=ROUNDUP(42, A1)', '=ROUNDUP(A1, FOO())'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-row.spec.ts b/test/unit/interpreter/function-row.spec.ts deleted file mode 100644 index e07fac26fb..0000000000 --- a/test/unit/interpreter/function-row.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ROW', () => { - it('should take one or zero arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROW(B1, B2)'], - ['=ROW(B1, B2, B3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should take only reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROW(42)'], - ['=ROW("foo")'], - ['=ROW(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.CellRefExpected)) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROW(1/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return row of a reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROW(B1)'], - ['=ROW(B7)'], - ['=ROW(F$5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(7) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - }) - - it('should work for itself', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROW(A1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should return row of a cell in which formula is', () => { - const engine = HyperFormula.buildFromArray([ - [null, '=ROW()'], - ['=ROW()'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - }) - - it('should return row of range start', () => { - const engine = HyperFormula.buildFromArray([ - ['=ROW(A3:A4)'], - ['=ROW(B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('should be dependent on sheet structure changes', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=ROW(A1)'] - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - - engine.addRows(0, [0, 1]) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/function-rows.spec.ts b/test/unit/interpreter/function-rows.spec.ts deleted file mode 100644 index 4316f07589..0000000000 --- a/test/unit/interpreter/function-rows.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function ROWS', () => { - it('accepts exactly one argument', () => { - const engine = HyperFormula.buildFromArray([['=ROWS()', '=ROWS(A2:A3, B2:B4)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for range', () => { - const engine = HyperFormula.buildFromArray([['=ROWS(A1:C2)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('works for row range', () => { - const engine = HyperFormula.buildFromArray([['=ROWS(1:3)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works for column range', () => { - const engine = HyperFormula.buildFromArray([['=ROWS(A:C)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(engine.getConfig().maxRows) - }) - - it('works for array', () => { - const engine = HyperFormula.buildFromArray([['=ROWS({1;2;3})']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works with cell reference', () => { - const engine = HyperFormula.buildFromArray([['=ROWS(A1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('propagates only direct errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=4/0'], - ['=ROWS(4/0)'], - ['=ROWS(A1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - // Inconsistency with Product 1 - it('works with formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['1', '1'], - ['=ROWS(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - }) - - it('should work when adding column', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=ROWS(A1:A2)'], - ['1'], - ]) - - engine.addRows(0, [1, 1]) - - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) -}) diff --git a/test/unit/interpreter/function-rri.spec.ts b/test/unit/interpreter/function-rri.spec.ts deleted file mode 100644 index bbe8607392..0000000000 --- a/test/unit/interpreter/function-rri.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function RRI', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=RRI(1,1)', '=RRI(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=RRI(1, 2, 1)', '=RRI(2, 1, 2)', '=RRI(0.1, 2, 1)'], - ['=RRI(1, -1, -1)', '=RRI(1, -1, 1)', '=RRI(1, 1, -1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-0.5) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.414213562373095) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(-0.9990234375) - //inconsistency with product #1 (returns #NUM!) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.NUM)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.NUM)) - }) -}) diff --git a/test/unit/interpreter/function-rsq.spec.ts b/test/unit/interpreter/function-rsq.spec.ts deleted file mode 100644 index b593d4b62f..0000000000 --- a/test/unit/interpreter/function-rsq.spec.ts +++ /dev/null @@ -1,92 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('RSQ', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=RSQ(B1:B5)'], - ['=RSQ(B1:B5, C1:C5, D1:D5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('ranges need to have same amount of elements', () => { - const engine = HyperFormula.buildFromArray([ - ['=RSQ(B1:B5, C1:C6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('works (simple)', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['2', '20'], - ['=RSQ(A1:A2, B1:B2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBe(1) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '4'], - ['5', '3'], - ['7', '6'], - ['1', '1'], - ['8', '5'], - ['=RSQ(A1:A5, B1:B5)'] - ]) - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(0.628378378378378) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=RSQ(A1:A1, B1:B1)'], - ['=RSQ(42, 43)'], - ['=RSQ("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['="2"', '50'], - ['3', '30'], - ['=RSQ(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=RSQ(MMULT(A1:B2, A1:B2), MMULT(B1:C2, B1:C2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.998496749220189, 6) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=4/0', '50'], - ['3', '30'], - ['=RSQ(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-search.spec.ts b/test/unit/interpreter/function-search.spec.ts deleted file mode 100644 index be47f9f734..0000000000 --- a/test/unit/interpreter/function-search.spec.ts +++ /dev/null @@ -1,157 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SEARCH', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH()'], - ['=SEARCH("foo")'], - ['=SEARCH("foo", 1, 2, 3)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return VALUE when wrong type of third parameter', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH("foo", "bar", "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should return VALUE if third parameter is not between 1 and text length', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH("foo", "bar", 0)'], - ['=SEARCH("foo", "bar", -1)'], - ['=SEARCH("foo", "bar", 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LengthBounds)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LengthBounds)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LengthBounds)) - }) - - it('should work with simple strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH("f", "foo")'], - ['=SEARCH("o", "foo")'], - ['=SEARCH("o", "foo", 3)'], - ['=SEARCH("g", "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - }) - - it('should work with wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH("*f", "foobarbaz")'], - ['=SEARCH("b*b", "foobarbaz")'], - ['=SEARCH("b?z", "foobarbaz")'], - ['=SEARCH("b?b", "foobarbaz")'], - ['=SEARCH("?b", "foobarbaz", 5)'], - ['=SEARCH("?b~", "foobarb~az", 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(4) - expect(engine.getCellValue(adr('A3'))).toEqual(7) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - expect(engine.getCellValue(adr('A5'))).toEqual(6) - expect(engine.getCellValue(adr('A6'))).toEqual(6) - }) - - it('should work with regular expressions', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH(".*f", "foobarbaz")'], - ['=SEARCH("b.*b", "foobarbaz")'], - ['=SEARCH("b.z", "foobarbaz")'], - ['=SEARCH("b.b", "foobarbaz")'], - ['=SEARCH(".b", "foobarbaz", 5)'], - ['=SEARCH(".B", "fooBarBaz")'], - ['=SEARCH(".B", "fooBarBaz", 5)'], - ['=SEARCH(".b", "fooBarBaz")'], - ['=SEARCH(".b", "fooBarBaz", 5)'], - ], {useRegularExpressions: true}) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(4) - expect(engine.getCellValue(adr('A3'))).toEqual(7) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - expect(engine.getCellValue(adr('A5'))).toEqual(6) - expect(engine.getCellValue(adr('A6'))).toEqual(3) - expect(engine.getCellValue(adr('A7'))).toEqual(6) - expect(engine.getCellValue(adr('A8'))).toEqual(3) - expect(engine.getCellValue(adr('A9'))).toEqual(6) - }) - - it('should work with regular expressions also when "caseSensitive: true" is set', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH(".*f", "foobarbaz")'], - ['=SEARCH("b.*b", "foobarbaz")'], - ['=SEARCH("b.z", "foobarbaz")'], - ['=SEARCH("b.b", "foobarbaz")'], - ['=SEARCH(".b", "foobarbaz", 5)'], - ['=SEARCH(".B", "fooBarBaz")'], - ['=SEARCH(".B", "fooBarBaz", 5)'], - ['=SEARCH(".b", "fooBarBaz")'], - ['=SEARCH(".b", "fooBarBaz", 5)'], - ], { useRegularExpressions: true, caseSensitive: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(4) - expect(engine.getCellValue(adr('A3'))).toEqual(7) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.PatternNotFound)) - expect(engine.getCellValue(adr('A5'))).toEqual(6) - expect(engine.getCellValue(adr('A6'))).toEqual(3) - expect(engine.getCellValue(adr('A7'))).toEqual(6) - expect(engine.getCellValue(adr('A8'))).toEqual(3) - expect(engine.getCellValue(adr('A9'))).toEqual(6) - }) - - it('should be case insensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH("R", "bar")'], - ['=SEARCH("r", "baR")'], - ['=SEARCH("?R", "bar")'], - ['=SEARCH("*r", "baR")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('should be case insensitive even when "caseSensitive: true" is set', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH("R", "bar")'], - ['=SEARCH("r", "baR")'], - ['=SEARCH("?R", "bar")'], - ['=SEARCH("*r", "baR")'], - ], { caseSensitive: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEARCH(1, 1, 1)'], - ['=SEARCH(0, 5+5)'], - ['=SEARCH("U", TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) -}) diff --git a/test/unit/interpreter/function-sec.spec.ts b/test/unit/interpreter/function-sec.spec.ts deleted file mode 100644 index 8f5c72a5e6..0000000000 --- a/test/unit/interpreter/function-sec.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SEC', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=SEC(0)', '=SEC(1)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.85081571768093) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=SEC("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=SEC()', '=SEC(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=SEC(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.85081571768093) - }) - - it('close to div/zero', () => { - const engine = HyperFormula.buildFromArray([ - [1.57079632679486, '=SEC(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(27249001701268.1, -3) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=SEC(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-sech.spec.ts b/test/unit/interpreter/function-sech.spec.ts deleted file mode 100644 index d4c0ef5664..0000000000 --- a/test/unit/interpreter/function-sech.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SECH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=SECH(0)', '=SECH(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.886818883970074) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=SECH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=SECH()', '=SECH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=SECH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.648054273663886) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=SECH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-second.spec.ts b/test/unit/interpreter/function-second.spec.ts deleted file mode 100644 index eef2653bf7..0000000000 --- a/test/unit/interpreter/function-second.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SECOND', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=SECOND("foo")', '=SECOND("12/30/2018")', '=SECOND(1, 2)', '=SECOND()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([['=SECOND(0.5123456)', '=SECOND(0)', '=SECOND(0.999999)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(47) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=SECOND("14:42:59")', '=SECOND("01/01/1900 03:01:02am")', '=SECOND("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(59) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - - it('use datenumber coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=SECOND(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=SECOND(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-seriessum.spec.ts b/test/unit/interpreter/function-seriessum.spec.ts deleted file mode 100644 index 77eedea191..0000000000 --- a/test/unit/interpreter/function-seriessum.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SERIESSUM', () => { - it('checks required number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SERIESSUM(1,2,3)'], - ['=SERIESSUM(1,2,3,4,5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('computes correct answer', () => { - const engine = HyperFormula.buildFromArray([ - ['=SERIESSUM(2,3,4,A2:D2)'], - [1, 2, 3, 4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(137480) - }) - - it('ignores nulls', () => { - const engine = HyperFormula.buildFromArray([ - ['=SERIESSUM(2,3,4,A2:D2)'], - [1, null, 3, 4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(8584) - }) - - it('throws error for non-numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=SERIESSUM(2,3,4,A2:D2)'], - [1, '\'1', 3, 4] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberExpected)) - }) - - it('works for non-integer args', () => { - const engine = HyperFormula.buildFromArray([ - ['=SERIESSUM(2,3.1,4,A3:D3)'], - ['=SERIESSUM(2,3,4.1,A3:D3)'], - [1, 2, 3, 4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(147347.41562949, 5) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(168708.537245456, 5) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=SERIESSUM(2,3,4,A2:D2)'], - [1, '=NA()', 3, 4] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-sheet.spec.ts b/test/unit/interpreter/function-sheet.spec.ts deleted file mode 100644 index d4864e287d..0000000000 --- a/test/unit/interpreter/function-sheet.spec.ts +++ /dev/null @@ -1,88 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SHEET', () => { - it('should return formula sheet number', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SHEET()']], - 'Sheet2': [['=SHEET()']], - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A1', 1))).toEqual(2) - }) - - it('should return reference sheet number for self sheet reference', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SHEET(B1)']], - 'Sheet2': [['=SHEET(B1)', '=1/0']], - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A1', 1))).toEqual(2) - }) - - it('should return reference sheet number for absolute sheet reference', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SHEET(Sheet1!B1)', '=SHEET(Sheet2!B1)']], - 'Sheet2': [['=SHEET(Sheet1!B1)', '=SHEET(Sheet2!B2)']], - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('A1', 1))).toEqual(1) - expect(engine.getCellValue(adr('B1', 1))).toEqual(2) - }) - - it('should return range sheet number', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SHEET(B1:B2)', '=SHEET(Sheet2!A1:B1)']], - 'Sheet2': [['=SHEET(B1:B2)', '=SHEET(Sheet1!A1:B1)']], - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - expect(engine.getCellValue(adr('A1', 1))).toEqual(2) - expect(engine.getCellValue(adr('B1', 1))).toEqual(1) - }) - - it('should return VALUE for non existing sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SHEET("FOO")', '=SHEET(1)']], - }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.SheetRef)) - }) - - it('should coerce', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addSheet('TRUE') - engine.addSheet('1') - - engine.setCellContents(adr('A1'), [['=SHEET(1=1)']]) - engine.setCellContents(adr('B1'), [['=SHEET(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([['=SHEET(1/0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should work for itself', () => { - const engine = HyperFormula.buildFromArray([['=SHEET(A1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should make cycle for non-refs', () => { - const engine = HyperFormula.buildFromArray([['=SHEET(1+A1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.CYCLE)) - }) -}) diff --git a/test/unit/interpreter/function-sheets.spec.ts b/test/unit/interpreter/function-sheets.spec.ts deleted file mode 100644 index 4435d71a71..0000000000 --- a/test/unit/interpreter/function-sheets.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SHEETS', () => { - it('should return number of sheets if no argument provided', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SHEETS()']], - 'Sheet2': [], - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('should return 1 for a valid reference', () => { - const engine = HyperFormula.buildFromArray([['=SHEETS(B1)', '=SHEETS(A1:A2)', '=SHEETS(A:B)', '=SHEETS(1:2)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('D1'))).toEqual(1) - }) - - it('should return VALUE for non-reference parameter', () => { - const engine = HyperFormula.buildFromArray([['=SHEETS(1)', '=SHEETS("foo")', '=SHEETS(TRUE())']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CellRefExpected)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CellRefExpected)) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([['=SHEETS(1/0)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should work for itself', () => { - const engine = HyperFormula.buildFromArray([['=SHEETS(A1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) -}) diff --git a/test/unit/interpreter/function-sign.spec.ts b/test/unit/interpreter/function-sign.spec.ts deleted file mode 100644 index b7aafd1b5a..0000000000 --- a/test/unit/interpreter/function-sign.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SIGN', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SIGN()'], - ['=SIGN(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=SIGN("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=SIGN(5)'], - ['=SIGN(0)'], - ['=SIGN(-12.1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toEqual(-1) - }) -}) diff --git a/test/unit/interpreter/function-sin.spec.ts b/test/unit/interpreter/function-sin.spec.ts deleted file mode 100644 index 4c3f4ffadf..0000000000 --- a/test/unit/interpreter/function-sin.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SIN', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=SIN(0)', '=SIN(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.479425538604203) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=SIN("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=SIN()', '=SIN(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=SIN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.841470984807897) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=SIN(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-sinh.spec.ts b/test/unit/interpreter/function-sinh.spec.ts deleted file mode 100644 index 54bc18ba7b..0000000000 --- a/test/unit/interpreter/function-sinh.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SINH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=SINH(0)', '=SINH(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.521095305493747) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=SINH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=SINH()', '=SINH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=SINH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-1.1752011936438) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=SINH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-skew.p.spec.ts b/test/unit/interpreter/function-skew.p.spec.ts deleted file mode 100644 index 340769c7f2..0000000000 --- a/test/unit/interpreter/function-skew.p.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SKEW.P', () => { - it('simple case', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW.P(1, 2, 4, 8)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.6568077345, 6) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '9', '0', '10'], - ['=SKEW.P(A1:D1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0164833284967738, 6) - }) - - it('propagates error from regular argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=SKEW.P(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('propagates first error from range argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=FOO(', '=SKEW.P(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - /** - * product #1 does not coerce the input - */ - it('does coercions of nonnumeric explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW.P(TRUE(),FALSE(),)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.707106781186548, 6) - }) - - it('ignores nonnumeric values in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW.P(A2:F2)'], - [1, 0, 0, false, null, '\'0'] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.707106781186548, 6) - }) - - it('validates range size', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW.P(0,0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.ThreeValues)) - }) -}) diff --git a/test/unit/interpreter/function-skew.spec.ts b/test/unit/interpreter/function-skew.spec.ts deleted file mode 100644 index f49fbbcbdf..0000000000 --- a/test/unit/interpreter/function-skew.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SKEW', () => { - it('simple case', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW(1, 2, 4, 8)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.137624367, 6) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '9', '0', '10'], - ['=SKEW(A1:D1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.02854996243, 6) - }) - - it('propagates error from regular argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=SKEW(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('propagates first error from range argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=NA()', '=FOO(', '=SKEW(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - /** - * product #1 does not coerce the input - */ - it('does coercions of nonnumeric explicit arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW(TRUE(),FALSE(),)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.732050808, 6) - }) - - it('ignores nonnumeric values in ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW(A2:F2)'], - [1, 0, 0, false, null, '\'0'] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.732050808, 6) - }) - - it('validates range size', () => { - const engine = HyperFormula.buildFromArray([ - ['=SKEW(0,0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.ThreeValues)) - }) -}) diff --git a/test/unit/interpreter/function-sln.spec.ts b/test/unit/interpreter/function-sln.spec.ts deleted file mode 100644 index b873f6e769..0000000000 --- a/test/unit/interpreter/function-sln.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SLN', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SLN(1,1)', '=SLN(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=SLN(1, 2, 1)', '=SLN(2, 1, -2)', '=SLN(3, 2, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-1) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.5) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-slope.spec.ts b/test/unit/interpreter/function-slope.spec.ts deleted file mode 100644 index ef49acddcb..0000000000 --- a/test/unit/interpreter/function-slope.spec.ts +++ /dev/null @@ -1,93 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('SLOPE', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SLOPE(B1:B5)'], - ['=SLOPE(B1:B5, C1:C5, D1:D5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('ranges need to have same amount of elements', () => { - const engine = HyperFormula.buildFromArray([ - ['=SLOPE(B1:B5, C1:C6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('works (simple)', () => { - const engine = HyperFormula.buildFromArray([ - [0, 0, 1], - [0, 1, 0], - ['=SLOPE(A1:C1, A2:C2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(-0.5) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '4'], - ['5', '3'], - ['7', '6'], - ['1', '1'], - ['8', '5'], - ['=SLOPE(A1:A5, B1:B5)'] - ]) - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(1.256756757, 6) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=SLOPE(A1:A1, B1:B1)'], - ['=SLOPE(42, 43)'], - ['=SLOPE("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - [0, 0], - ['="2"', '50'], - [1, 0], - [0, 1], - ['=SLOPE(A1:A4, B1:B4)'], - ]) - - expect(engine.getCellValue(adr('A5'))).toEqual(-0.5) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=SLOPE(MMULT(A1:B2, A1:B2), MMULT(B1:C2, B1:C2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.75346687211094, 6) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=NA()', '50'], - ['3', '30'], - ['=SLOPE(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-small.spec.ts b/test/unit/interpreter/function-small.spec.ts deleted file mode 100644 index b7b239f564..0000000000 --- a/test/unit/interpreter/function-small.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SMALL', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SMALL(1)'], - ['=SMALL(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=SMALL(1, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=SMALL(A2:D2,0)', '=SMALL(A2:D2,1)', '=SMALL(A2:D2,2)', '=SMALL(A2:D2,3)', '=SMALL(A2:D2,4)', '=SMALL(A2:D2,5)'], - [1, 4, 2, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(2) - expect(engine.getCellValue(adr('D1'))).toEqual(4) - expect(engine.getCellValue(adr('E1'))).toEqual(4) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('should ignore non-numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=SMALL(A2:D2,0)', '=SMALL(A2:D2,1)', '=SMALL(A2:D2,2)', '=SMALL(A2:D2,3)'], - [1, 4, true, 'abcd'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(4) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=SMALL(A2:D2,0)', '=SMALL(A2:D2,1)', '=SMALL(A2:D2,2)', '=SMALL(A2:D2,3)'], - [1, 4, '=NA()', 'abcd'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should truncate second arg', () => { - const engine = HyperFormula.buildFromArray([ - ['=SMALL(A2:D2,0.9)', '=SMALL(A2:D2,1.9)', '=SMALL(A2:D2,2.9)', '=SMALL(A2:D2,3.9)', '=SMALL(A2:D2,4.9)', '=SMALL(A2:D2,5.9)'], - [1, 4, 2, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqual(2) - expect(engine.getCellValue(adr('D1'))).toEqual(4) - expect(engine.getCellValue(adr('E1'))).toEqual(4) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) - - it('should work for non-ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=SMALL(1,0)', '=SMALL(1,1)', '=SMALL(1,2)', '=SMALL(TRUE(),1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toEqual(1) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - }) -}) diff --git a/test/unit/interpreter/function-split.spec.ts b/test/unit/interpreter/function-split.spec.ts deleted file mode 100644 index 16bebe4bac..0000000000 --- a/test/unit/interpreter/function-split.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SPLIT', () => { - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=SPLIT(1)', '=SPLIT("a","b","c")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['some words', '=SPLIT(A1, 0)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual('some') - }) - - it('bigger index', () => { - const engine = HyperFormula.buildFromArray([['some words', '=SPLIT(A1, 1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual('words') - }) - - it('when continuous delimeters', () => { - const engine = HyperFormula.buildFromArray([['some words', '=SPLIT(A1, 1)', '=SPLIT(A1, 2)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual('') - expect(engine.getCellValue(adr('C1'))).toEqual('words') - }) - - it('coerce first argument to string', () => { - const engine = HyperFormula.buildFromArray([['42', '=SPLIT(A1, 1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IndexBounds)) - }) - - it('when 2nd arg not a number', () => { - const engine = HyperFormula.buildFromArray([['some words', '=SPLIT(A1, "foo")']]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('when index arg is not value within bounds', () => { - const engine = HyperFormula.buildFromArray([['some words', '=SPLIT(A1, 17)', '=SPLIT(A1, -1)']]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IndexBounds)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IndexBounds)) - }) -}) diff --git a/test/unit/interpreter/function-sqrt.spec.ts b/test/unit/interpreter/function-sqrt.spec.ts deleted file mode 100644 index 11ffd2337e..0000000000 --- a/test/unit/interpreter/function-sqrt.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SQRT', () => { - it('should return error for negative numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=SQRT(-2)'], - ['=SQRT(-2)+1'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SQRT()'], - ['=SQRT(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=SQRT("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=SQRT(0)'], - ['=SQRT(16)'], - ['=SQRT(2)'], - ], {smartRounding: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toEqual(4) - expect(engine.getCellValue(adr('A3'))).toEqual(1.4142135623730951) - }) -}) diff --git a/test/unit/interpreter/function-sqrtpi.spec.ts b/test/unit/interpreter/function-sqrtpi.spec.ts deleted file mode 100644 index 101c15d41a..0000000000 --- a/test/unit/interpreter/function-sqrtpi.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SQRTPI', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SQRTPI()', '=SQRTPI(1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=SQRTPI(0)'], - ['=SQRTPI(1)'], - ['=SQRTPI(PI())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.77245385090552, 6) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(3.14159265358979, 6) - }) - - it('pass error', () => { - const engine = HyperFormula.buildFromArray([ - ['=SQRTPI(NA())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-standardize.spec.ts b/test/unit/interpreter/function-standardize.spec.ts deleted file mode 100644 index de5e9ee615..0000000000 --- a/test/unit/interpreter/function-standardize.spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function STANDARDIZE', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=STANDARDIZE(1, 2)'], - ['=STANDARDIZE(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=STANDARDIZE("foo", 1, 2)'], - ['=STANDARDIZE(1, "foo", 2)'], - ['=STANDARDIZE(1, 2, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=STANDARDIZE(1, 2, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-0.25) - }) - - it('should check bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=STANDARDIZE(1, 2, 0.001)'], - ['=STANDARDIZE(1, 2, 0)'], - ['=STANDARDIZE(1, 2, -0.001)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(-1000) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-stdev.p.spec.ts b/test/unit/interpreter/function-stdev.p.spec.ts deleted file mode 100644 index 2e3ae7fc54..0000000000 --- a/test/unit/interpreter/function-stdev.p.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function STDEV.P', () => { - it('should take at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.P()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate standard deviation (population)', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.P(2, 3)'], - ['=STDEV.P(1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.P(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.39970842444753, 6) //inconsistency with product #1 - }) - - it('should ignore non-numeric values in ranges, including ignoring logical values and text representation of numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.P(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.816496580927726, 6) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.P(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-stdev.s.spec.ts b/test/unit/interpreter/function-stdev.s.spec.ts deleted file mode 100644 index 4fb94c8570..0000000000 --- a/test/unit/interpreter/function-stdev.s.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function STDEV.S', () => { - it('should take at least two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.S()'], - ['=STDEV.S(1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should calculate standard deviation (sample)', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.S(2, 3)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.707106781186548, 6) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.S(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.51185789203691, 6) //inconsistency with product #1 - }) - - it('should ignore non-numeric values in ranges, including ignoring logical values and text representation of numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.S(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEV.S(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-stdeva.spec.ts b/test/unit/interpreter/function-stdeva.spec.ts deleted file mode 100644 index 7a309e800d..0000000000 --- a/test/unit/interpreter/function-stdeva.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function STDEVA', () => { - it('should take at least two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVA()'], - ['=STDEVA(1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should calculate standard deviation (sample)', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVA(2, 3)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.707106781186548, 11) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVA(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.51185789203691) - }) - - it('should evaluate TRUE to 1, FALSE to 0 and text to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVA(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.61834718742537) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVA(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-stdevpa.spec.ts b/test/unit/interpreter/function-stdevpa.spec.ts deleted file mode 100644 index b74b51749b..0000000000 --- a/test/unit/interpreter/function-stdevpa.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function STDEVPA', () => { - it('should take at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVPA()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate standard deviation (population)', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVPA(2, 3)'], - ['=STDEVPA(1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVPA(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.39970842444753, 6) - }) - - it('should evaluate TRUE to 1, FALSE to 0 and text to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVPA(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.49829835452879, 6) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=STDEVPA(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-steyx.spec.ts b/test/unit/interpreter/function-steyx.spec.ts deleted file mode 100644 index 753f2dafd7..0000000000 --- a/test/unit/interpreter/function-steyx.spec.ts +++ /dev/null @@ -1,93 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('STEYX', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=STEYX(B1:B5)'], - ['=STEYX(B1:B5, C1:C5, D1:D5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('ranges need to have same amount of elements', () => { - const engine = HyperFormula.buildFromArray([ - ['=STEYX(B1:B5, C1:C6)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('works (simple)', () => { - const engine = HyperFormula.buildFromArray([ - [0, 0, 1], - [0, 1, 0], - ['=STEYX(A1:C1, A2:C2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.7071067812, 6) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '4'], - ['5', '3'], - ['7', '6'], - ['1', '1'], - ['8', '5'], - ['=STEYX(A1:A5, B1:B5)'] - ]) - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(2.146650439, 6) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=STEYX(A1:B1, A1:B1)'], - ['=STEYX(42, 43)'], - ['=STEYX("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.ThreeValues)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.ThreeValues)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.ThreeValues)) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - [0, 0], - ['="2"', '50'], - [1, 0], - [0, 1], - ['=STEYX(A1:A4, B1:B4)'], - ]) - - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(0.707106781186548, 6) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['4', '5', '6'], - ['=STEYX(MMULT(A1:B2, A1:B2), MMULT(B1:C2, B1:C2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.526640075265055, 6) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=NA()', '50'], - ['3', '30'], - ['=STEYX(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-substitute.spec.ts b/test/unit/interpreter/function-substitute.spec.ts deleted file mode 100644 index 5f3b09687c..0000000000 --- a/test/unit/interpreter/function-substitute.spec.ts +++ /dev/null @@ -1,145 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SUBSTITUTE', () => { - it('should take three or four parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foo", "f")'], - ['=SUBSTITUTE("foobar", "o", "uu", 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should substitute new text for all occurrences of old text in a string', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foo", "f", "bb")'], - ['=SUBSTITUTE("foobar", "o", "uu")'], - ['=SUBSTITUTE("fooobar", "oo", "x")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('bboo') - expect(engine.getCellValue(adr('A2'))).toEqual('fuuuubar') - expect(engine.getCellValue(adr('A3'))).toEqual('fxobar') - }) - - it('should substitute new text for nth occurrence of a string', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foobar", "o", "f", 1)'], - ['=SUBSTITUTE("foobar", "o", "OO", 2)'], - ['=SUBSTITUTE("foobar", "o", "OO", 3)'], - ['=SUBSTITUTE("fofofofofo", "o", "u", 4)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('ffobar') - expect(engine.getCellValue(adr('A2'))).toEqual('foOObar') - expect(engine.getCellValue(adr('A3'))).toEqual('foobar') - expect(engine.getCellValue(adr('A4'))).toEqual('fofofofufo') - }) - - it('should return the original text if there are not enough occurrences of the search string', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foobar", "o", "BAZ", 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('foobar') - }) - - it('should accept "." character in the search string', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foo.bar", ".", "BAZ")'], - ['=SUBSTITUTE("foo.bar", "foo.", "BAZ")'], - ['=SUBSTITUTE("foo.bar", ".bar", "BAZ")'], - ['=SUBSTITUTE("foo.foo.foo.bar.", ".", "BAZ", 1)'], - ['=SUBSTITUTE("foo.foo.foo.bar.", ".", "BAZ", 2)'], - ['=SUBSTITUTE("foo.foo.foo.bar.", ".", "BAZ", 3)'], - ['=SUBSTITUTE("foo.foo.foo.bar.", ".", "BAZ", 4)'], - ['=SUBSTITUTE("foo.foo.foo.bar.", ".", "BAZ", 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A2'))).toEqual('BAZbar') - expect(engine.getCellValue(adr('A3'))).toEqual('fooBAZ') - expect(engine.getCellValue(adr('A4'))).toEqual('fooBAZfoo.foo.bar.') - expect(engine.getCellValue(adr('A5'))).toEqual('foo.fooBAZfoo.bar.') - expect(engine.getCellValue(adr('A6'))).toEqual('foo.foo.fooBAZbar.') - expect(engine.getCellValue(adr('A7'))).toEqual('foo.foo.foo.barBAZ') - expect(engine.getCellValue(adr('A8'))).toEqual('foo.foo.foo.bar.') - }) - - it('should accept regexp special characters in the search string', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foo[bar", "[", "BAZ")'], - ['=SUBSTITUTE("foo]bar", "]", "BAZ")'], - ['=SUBSTITUTE("foo-bar", "-", "BAZ")'], - ['=SUBSTITUTE("foo*bar", "*", "BAZ")'], - ['=SUBSTITUTE("foo+bar", "+", "BAZ")'], - ['=SUBSTITUTE("foo?bar", "?", "BAZ")'], - ['=SUBSTITUTE("foo^bar", "^", "BAZ")'], - ['=SUBSTITUTE("foo$bar", "$", "BAZ")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A2'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A3'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A4'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A5'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A6'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A7'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A8'))).toEqual('fooBAZbar') - }) - - it('should work with search strings that look like regular expressions', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foo.*bar", ".*", "BAZ")'], - ['=SUBSTITUTE("foo[a-z]+bar", "[a-z]+", "BAZ")'], - ['=SUBSTITUTE("foo[^-]bar", "[^-]", "BAZ")'], - ['=SUBSTITUTE("foo[^*]bar", "[^*]", "BAZ")'], - ['=SUBSTITUTE("foo/.*/bar", "/.*/", "BAZ")'], - ['=SUBSTITUTE("foo\\sbar", "\\s", "BAZ")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A2'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A3'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A4'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A5'))).toEqual('fooBAZbar') - expect(engine.getCellValue(adr('A6'))).toEqual('fooBAZbar') - }) - - it('should coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foobar", "o", TRUE(), 1)'], - ['=SUBSTITUTE("fooTRUE", TRUE(), 5, 1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('fTRUEobar') - expect(engine.getCellValue(adr('A2'))).toEqual('foo5') - }) - - it('should return value when last argument is less than one', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foobar", "o", "f", 0)'], - ['=SUBSTITUTE("foobar", "o", "OO", -1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('should return value when arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBSTITUTE("foobar", "o", "f", "bar")'], - ['=SUBSTITUTE(B1:C1, "o", "f", 3)'], - ['=SUBSTITUTE("foobar", B1:C1, "f", 3)'], - ['=SUBSTITUTE("foobar", "o", B1:C1, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) -}) diff --git a/test/unit/interpreter/function-subtotal.spec.ts b/test/unit/interpreter/function-subtotal.spec.ts deleted file mode 100644 index f99b78dd19..0000000000 --- a/test/unit/interpreter/function-subtotal.spec.ts +++ /dev/null @@ -1,173 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SUBTOTAL', () => { - it('should calculate AVERAGE', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(1, A2:A4, A5)', '=SUBTOTAL(101, A2:A4, A5)'], - [2], - [3], - [4], - [5] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3.5) - expect(engine.getCellValue(adr('B1'))).toEqual(3.5) - }) - - it('should calculate COUNT', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(2, A2:A4, A5)', '=SUBTOTAL(102, A2:A4, A5)'], - [2], - ['foo'], - [4], - [5] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) - - it('should calculate COUNTA', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(3, A2:A4, A5)', '=SUBTOTAL(103, A2:A4, A5)'], - [2], - ['foo'], - [4], - [5] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - expect(engine.getCellValue(adr('B1'))).toEqual(4) - }) - - it('should calcuate MAX', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(4, A2:A4, A5)', '=SUBTOTAL(104, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - expect(engine.getCellValue(adr('B1'))).toEqual(5) - }) - - it('should calculate MIN', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(5, A2:A4, A5)', '=SUBTOTAL(105, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - expect(engine.getCellValue(adr('B1'))).toEqual(2) - }) - - it('should calculate PRODUCT', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(6, A2:A4, A5)', '=SUBTOTAL(106, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(120) - expect(engine.getCellValue(adr('B1'))).toEqual(120) - }) - - it('should calculate STDEV.S', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(7, A2:A4, A5)', '=SUBTOTAL(107, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.29099444873581, 6) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.29099444873581, 6) - }) - - it('should calculate STDEV.P', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(8, A2:A4, A5)', '=SUBTOTAL(108, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.11803398875, 6) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(1.11803398875, 6) - }) - - it('should calculate SUM', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(9, A2:A4, A5)', '=SUBTOTAL(109, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(14) - expect(engine.getCellValue(adr('B1'))).toEqual(14) - }) - - it('should calculate VAR.S', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(10, A2:A4, A5)', '=SUBTOTAL(110, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(5 / 3, 6) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(5 / 3, 6) - }) - - it('should calculate VAR.P', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(11, A2:A4, A5)', '=SUBTOTAL(111, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(5 / 4) - expect(engine.getCellValue(adr('B1'))).toEqual(5 / 4) - }) - - it('should return correct error', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(12345, A2:A4, A5)'], - [3], - [5], - [2], - [4] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - }) - - /** - * Inconsistency with ODFF standard. - */ - it('does not ignore other SUBTOTALS', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUBTOTAL(9, A2:A4)'], - ['=SUBTOTAL(9, B2:C2)', 1, 1], - ['=SUBTOTAL(9, B3:C3)', 1, 1], - ['=SUBTOTAL(9, B4:C4)', 1, 1], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(6) - }) -}) diff --git a/test/unit/interpreter/function-sum.spec.ts b/test/unit/interpreter/function-sum.spec.ts deleted file mode 100644 index 5435b42a52..0000000000 --- a/test/unit/interpreter/function-sum.spec.ts +++ /dev/null @@ -1,254 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('SUM', () => { - it('SUM without args', () => { - const engine = HyperFormula.buildFromArray([['=SUM()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('SUM with args', () => { - const engine = HyperFormula.buildFromArray([['=SUM(1, B1)', '3.14']]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(4.14) - }) - - it('SUM with range args', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '5'], - ['3', '4', '=SUM(A1:B2)'] - ]) - expect(engine.getCellValue(adr('C2'))).toEqual(10) - }) - - it('SUM with column range args', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '5'], - ['3', '4', '=SUM(A:B)'] - ]) - expect(engine.getCellValue(adr('C2'))).toEqual(10) - }) - - it('SUM with using previously cached value', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '=SUM(A1:A1)'], - ['4', '=SUM(A1:A2)'], - ]) - expect(engine.getCellValue(adr('B2'))).toEqual(7) - }) - - it('doesnt do coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['foo'], - ['=TRUE()'], - ['=CONCATENATE("1","0")'], - ['=SUM(A1:A5)'], - ['=SUM(A3)'], - ['=SUM(A4)'], - ['=SUM(A5)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual(3) - expect(engine.getCellValue(adr('A7'))).toEqual(0) - expect(engine.getCellValue(adr('A8'))).toEqual(0) - expect(engine.getCellValue(adr('A9'))).toEqual(0) - }) - - it('works when precision (default setting)', () => { - const engine = HyperFormula.buildFromArray([ - ['1.00000000000005', '-1'], - ['=SUM(A1:B1)'] - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('explicitly called does coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(2,TRUE())'], - ['=SUM(2,"foo",TRUE())'], - ['=SUM(TRUE())'], - ['=SUM("10")'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(10) - }) - - it('doesnt take value from range if it does not store cached value for that function', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=MAX(A1:A2)'], - ['=SUM(A1:A3)'], - ]) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('range only with empty value', () => { - const engine = HyperFormula.buildFromArray([['', '=SUM(A1:A1)']]) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('range only with some empty values', () => { - const engine = HyperFormula.buildFromArray([['42', '', '13', '=SUM(A1:C1)']]) - expect(engine.getCellValue(adr('D1'))).toEqual(55) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=SUM(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(54) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=SUM(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works with a column range reference to an empty sheet', () => { - const hf = HyperFormula.buildFromSheets({ - table1: [], - table2: [['=SUM(table1!A:C)']], - }) - - expect(hf.getCellValue(adr('A1', 1))).toEqual(0) - }) - - it('accepts 100k parameters', () => { - const numOfParams = 100000 - const argsList = Array(numOfParams).fill('1').map((_, i) => `A${i+2}`).join(', ') - const formula = `=SUM(${argsList})` - - const engine = HyperFormula.buildFromArray([ - [formula], - ...Array(numOfParams).fill([1]) - ], { maxRows: numOfParams+2 }) - - expect(engine.getCellValue(adr('A1'))).toEqual(numOfParams) - }) - - describe('works with reversed cell ranges', () => { - it('simple case', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=SUM(A1:B2)'], - ['=SUM(A2:B1)'], - ['=SUM(B1:A2)'], - ['=SUM(B2:A1)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(10) - expect(engine.getCellValue(adr('A4'))).toEqual(10) - expect(engine.getCellValue(adr('A5'))).toEqual(10) - expect(engine.getCellValue(adr('A6'))).toEqual(10) - }) - - describe('that has the same R1C1 representation (may cause cache clash)', () => { - it('when 1st row address is absolute and one of the ranges is a single value', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B$2:B1)', 1], // R1C[+1]:R[+0]C[+1] - [' ', 2], - [' ', 3], - ['=SUM(B$2:B4)', 4], // R1C[+1]:R[+0]C[+1] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(9) - }) - - it('when 2nd row address is absolute and one of the ranges is a single value', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B1:B$2)', 1], // R[+0]C[+1]:R1C[+1] - [' ', 2], - [' ', 3], - ['=SUM(B4:B$2)', 4], // R[+0]C[+1]:R1C[+1] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(9) - }) - - it('when 1st row address is absolute and one of the ranges is a single value (2)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B$2:B1)', 1], // R1C[+1]:R[+0]C[+1] - ['=SUM(B$2:B2)', 2], // R1C[+1]:R[+0]C[+1] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - }) - - it('when 2nd row address is absolute and one of the ranges is a single value (2)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(B1:B$1)', 1], // R[+0]C[+1]:R0C[+1] - ['=SUM(B2:B$1)', 2], // R[+0]C[+1]:R0C[+1] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - }) - }) - - describe('works with reversed column ranges', () => { - it('when 1st address is absolute', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM($C:C)', '=SUM($C:D)', 1, 2], // C2:C[+2] // C2:C[+2] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) - - it('when 2nd address is absolute', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(C:$C)', '=SUM(D:$C)', 1, 2], // C[+2]:C2 // C[+2]:C2 - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('B1'))).toEqual(3) - }) - }) - - describe('works with reversed row ranges', () => { - it('when 1st address is absolute', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM($4:3)'], // R3:R[+2] - ['=SUM($4:4)'], // R3:R[+2] - [1], - [2], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - }) - - it('when 2nd address is absolute', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(3:$3)'], // R[+2]:R2 - ['=SUM(4:$3)'], // R[+2]:R2 - [1], - [2], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - }) -}) diff --git a/test/unit/interpreter/function-sumif.spec.ts b/test/unit/interpreter/function-sumif.spec.ts deleted file mode 100644 index 120e569dca..0000000000 --- a/test/unit/interpreter/function-sumif.spec.ts +++ /dev/null @@ -1,773 +0,0 @@ -import {CellValueDetailedType, HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {plPL} from '../../../src/i18n/languages' -import {StatType} from '../../../src/statistics' -import {adr, detailedError, expectArrayWithSameContent} from '../testUtils' - -describe('Function SUMIF - argument validations and combinations', () => { - it('requires 2 or 3 arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(C1)'], - ['=SUMIF(C1, ">0", C1, C1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works when 2nd arg is an integer', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(C1:C2, 1, B1:B2)', 2, 1], - [null, 3, true], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('works when 2nd arg is a string', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(C1:C2, "a", B1:B2)', 2, 'a'], - [null, 3, 'b'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('works when 2nd arg is an inline array', () => { - const engine = HyperFormula.buildFromArray([ - [2, 'a'], - [3, 'b'], - ['=SUMIF(B1:B2, {"a", "b"}, A1:A2)'] - ], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('B3'))).toEqual(3) - }) - - it('works with an array as a second argument', () => { - const engine = HyperFormula.buildFromArray([ - [null, 2, 1], - [null, 3, 2], - ['=SUMIF(C1:C2, { 1, 2 }, B1:B2)'] - ], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('B3'))).toEqual(3) - }) - - it('works when 2nd arg is a boolean', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(C1:C2, TRUE(), B1:B2)', 2, 1], - [null, 3, true], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works when 2nd arg is a string "true"', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(C1:C2, "=TRUE", B1:B2)', 2, 1], - [null, 3, true], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('works when 2nd arg is a string "true" in different language', () => { - HyperFormula.registerLanguage('plPL', plPL) - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(C1:C2, "=PRAWDA", B1:B2)', 2, 1], - [null, 3, true], - ], {language: 'plPL'}) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('error when criterion unparsable', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(B1:B2, "> { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(B1:C1, ">0", B2:D2)'], - ['=SUMIF(B1, ">0", B2:D2)'], - ['=SUMIF(B1:D1, ">0", B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('error when different height dimension of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(B1:B2, ">0", C1:C3)'], - ['=SUMIF(B1, ">0", C1:C2)'], - ['=SUMIF(B1:B2, ">0", C1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('error when number of elements match but dimensions doesnt', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(B1:B2, ">0", B1:C1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('scalars are treated like singular arrays', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(10, ">1", 42)'], - ['=SUMIF(0, ">1", 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIF(4/0, ">1", 42)'], - ['=SUMIF(0, 4/0, 42)'], - ['=SUMIF(0, ">1", 4/0)'], - ['=SUMIF(0, 4/0, FOOBAR())'], - ['=SUMIF(4/0, FOOBAR(), 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works when arguments are just references', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=SUMIF(A1, ">1", B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('works with range values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '3', '5'], - ['1', '1', '7', '9'], - ['=SUMIF(MMULT(A1:B2, A1:B2), "=2", MMULT(C1:D2, C1:D2))'], - ['=SUMIF(A1:B2, "=1", MMULT(C1:D2, C1:D2))'], - ['=SUMIF(MMULT(A1:B2, A1:B2), "=2", C1:D2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(304) - expect(engine.getCellValue(adr('A4'))).toEqual(304) - expect(engine.getCellValue(adr('A5'))).toEqual(24) - }) - - it('works for mixed reference/range arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=SUMIF(A1:A1, ">1", B1)'], - ['=SUMIF(A1, ">1", B1:B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('works for 2 arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['10', '20', '30'], - ['=SUMIF(A1:C1, ">15")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(50) - }) - - it('works for matrices', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=TRANSPOSE(A1:B1)'], - [], - ['=SUMIF(A2:A3, ">0", A2:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) -}) - -describe('Function SUMIF(S) - calculations and optimizations', () => { - it('no coercion when sum', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '="3"'], - ['=SUMIF(A1, ">1", B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('empty coercions', () => { - const engine = HyperFormula.buildFromArray([ - [1, null], - [2, 8], - [3, 9], - ['=SUMIF(B1:B3,"=",A1:A3)'], - ['=SUMIF(B1:B3,">=",A1:A3)'], - ['=SUMIF(B1:B3,"<=",A1:A3)'], - ['=SUMIF(B1:B3,"<>",A1:A3)'], - ]) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toEqual(0) - expect(engine.getCellValue(adr('A7'))).toEqual(5) - }) - - it('works for subranges with different conditions', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '=SUMIF(A1:A1,"="&A1,B1:B1)'], - ['2', '1', '=SUMIF(A1:A2,"="&A2,B1:B2)'], - ['1', '1', '=SUMIF(A1:A3,"="&A3,B1:B3)'], - ['3', '1', '=SUMIF(A1:A4,"="&A4,B1:B4)'], - ['1', '1', '=SUMIF(A1:A5,"="&A5,B1:B5)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('C2'))).toEqual(1) - expect(engine.getCellValue(adr('C3'))).toEqual(2) - expect(engine.getCellValue(adr('C4'))).toEqual(1) - expect(engine.getCellValue(adr('C5'))).toEqual(3) - }) - - it('works for subranges with inequality', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '=SUMIF(A1:A1,">2",B1:B1)'], - ['2', '1', '=SUMIF(A1:A2,">2",B1:B2)'], - ['3', '1', '=SUMIF(A1:A3,">2",B1:B3)'], - ['4', '1', '=SUMIF(A1:A4,">2",B1:B4)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(0) - expect(engine.getCellValue(adr('C2'))).toEqual(0) - expect(engine.getCellValue(adr('C3'))).toEqual(1) - expect(engine.getCellValue(adr('C4'))).toEqual(2) - }) - - it('works for subranges with more interesting criterions', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '=SUMIF(A1:A1,"=1",B1:B1)'], - ['2', '1', '=SUMIF(A1:A2,"<=2",B1:B2)'], - ['1', '1', '=SUMIF(A1:A3,"<2",B1:B3)'], - ['1', '1', '=SUMIF(A1:A4,">4",B1:B4)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('C2'))).toEqual(2) - expect(engine.getCellValue(adr('C3'))).toEqual(2) - expect(engine.getCellValue(adr('C4'))).toEqual(0) - }) - - it('discontinuous sumif range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '=SUMIF(A1:A1,"="&A1,B1:B1)'], - ['2', '1', '=SUMIF(A1:A2,"="&A2,B1:B2)'], - ['1', '1', '=SUMIF(A1:A3,"="&A3,B1:B3)'], - ['0', '0', '0'], - ['1', '1', '=SUMIF(A1:A5,"="&A5,B1:B5)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('C2'))).toEqual(1) - expect(engine.getCellValue(adr('C3'))).toEqual(2) - expect(engine.getCellValue(adr('C5'))).toEqual(3) - }) - - it('using full cache', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A3, "=1", B1:B3)'], - ['=SUMIF(A1:A3, "=1", B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(5) - expect(engine.getCellValue(adr('A5'))).toEqual(5) - expect(engine.getStats().get(StatType.CRITERION_FUNCTION_FULL_CACHE_USED)).toEqual(1) - }) - - it('works with different sheets', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [ - ['0', '3'], - ['1', '5'], - ['2', '7'], - ['=SUMIF(A1:A3, "=1", B1:B3)'], - ['=SUMIF(Sheet2!A1:A3, "=1", B1:B3)'], - ], - Sheet2: [ - ['0', '30'], - ['0', '50'], - ['1', '70'], - ['=SUMIF(A1:A3, "=1", B1:B3)'], - ], - }) - - expect(engine.getCellValue(adr('A4', 0))).toEqual(5) - expect(engine.getCellValue(adr('A5', 0))).toEqual(7) - expect(engine.getCellValue(adr('A4', 1))).toEqual(70) - expect(engine.getStats().get(StatType.CRITERION_FUNCTION_FULL_CACHE_USED)).toEqual(0) - }) - - it('works when precision sensitive (default setting)', () => { - const engine = HyperFormula.buildFromArray([ - ['1.0000000001', '1'], - ['1.00000000000005', '2'], - ['1.00000000000005', '4'], - ['=SUMIF(A1:A3, "=1", B1:B3)'] - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(6) - }) - - it('criterions are not accent sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['ABCD', '2'], - ['abc', '4'], - ['=SUMIF(A1:A3, "=ąbcd", B1:B3)'] - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('criterions are accent sensitive if specified', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['ABCD', '2'], - ['abc', '4'], - ['=SUMIF(A1:A3, "=ąbcd", B1:B3)'] - ], {accentSensitive: true}) - - expect(engine.getCellValue(adr('A4'))).toEqual(0) - }) - - it('criterions are not case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['ABCD', '2'], - ['abc', '4'], - ['=SUMIF(A1:A3, "<>abcd", B1:B3)'] - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('criterions are not case sensitive 2', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['ABCD', '2'], - ['abc', '4'], - ['=SUMIF(A1:A3, "=abcd", B1:B3)'] - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(3) - }) - - it('criterions are case sensitive if specified', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['ABCD', '2'], - ['abc', '4'], - ['=SUMIF(A1:A3, "<>abcd", B1:B3)'] - ], {caseSensitive: true}) - - expect(engine.getCellValue(adr('A4'))).toEqual(6) - }) - - it('usage of wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['ABCD', '2'], - ['abc', '4'], - [0, 8], - ['=SUMIF(A1:A4, "=a?c*", B1:B4)'] - ]) - - expect(engine.getCellValue(adr('A5'))).toEqual(7) - }) - - it('wildcards instead of regexps', () => { - const engine = HyperFormula.buildFromArray([ - ['a+?*', '1'], - ['a?*', '2'], - ['aa~?~*', '4'], - [0, 8], - ['=SUMIF(A1:A4, "=a+~?~*", B1:B4)'] - ]) - - expect(engine.getCellValue(adr('A5'))).toEqual(1) - }) - - it('regexp', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['abd', '2'], - ['.*c.*', '4'], - [0, 8], - ['=SUMIF(A1:A4, ".*c.*", B1:B4)'] - ], {useRegularExpressions: true}) - - expect(engine.getCellValue(adr('A5'))).toEqual(5) - }) - - it('regexp with not-equal operator', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['abd', '2'], - ['.*c.*', '4'], - [0, 8], - ['=SUMIF(A1:A4, "<>.*c.*", B1:B4)'] - ], {useRegularExpressions: true}) - - expect(engine.getCellValue(adr('A5'))).toEqual(10) - }) - - it('incorrect regexp', () => { - const engine = HyperFormula.buildFromArray([ - ['abcd', '1'], - ['abd', '2'], - ['.*c.*', '4'], - [0, 8], - ['=SUMIF(A1:A4, "=)", B1:B4)'] - ], {useRegularExpressions: true}) - - expect(engine.getCellValue(adr('A5'))).toEqual(0) - }) - - it('ignore errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '3'], - ['=4/0', '5'], - ['2', '=4/0'], - ['1', '10'], - ['=SUMIF(A1:A4, "=1", B1:B4)'], - ]) - - expect(engine.getCellValue(adr('A5'))).toEqual(13) - }) - - it('coerces dates as numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '9160250011660588', '43469', '25000'], - ['2', '9160250011689568', '43631', '15000'], - ['=SUMIF(C2:C11,">31/05/2019",D2:D11)'] - ], {dateFormats: ['DD/MM/YYYY']}) - expect(engine.getCellValue(adr('A3'))).toEqual(15000) - }) - - it('works when criterion arg is a date', () => { - const engine = HyperFormula.buildFromArray([ - ['31/05/2019', '1'], - ['=DATEVALUE("31/05/2019")', '1'], - ['=DATE(2019, 5, 31)', '1'], - ['=A1', '1'], - ['43616', '1'], - ['=SUMIF(A1:A5, "31/05/2019", B1:B5)'] - ], {dateFormats: ['DD/MM/YYYY']}) - - expect(engine.getCellValue(adr('A6'))).toEqual(5) - }) - - it('works when criterion arg is a time value', () => { - const engine = HyperFormula.buildFromArray([ - ['12:13', '1'], - ['=SUMIF(A1:A1, "12:13", B1:B1)'] - ]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('works when criterion arg is a datetime value', () => { - const engine = HyperFormula.buildFromArray([ - ['31/05/2019 9:15', '1'], - ['=SUMIF(A1:A1, "31/05/2019 9:15", B1:B1)'] - ]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('works when criterion arg is a currency value', () => { - const engine = HyperFormula.buildFromArray([ - ['$1', '1'], - ['1$', '1'], - ['=SUMIF(A1:A2, "$1", B1:B2)'], - ['=SUMIF(A1:A2, "1$", B1:B2)'] - ]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('A4'))).toEqual(2) - }) - - it('works when criterion arg is a percent value', () => { - const engine = HyperFormula.buildFromArray([ - ['20%', '1'], - ['=SUMIF(A1:A1, "20%", B1:B1)'] - ]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - }) - - it('ignores whitespace characters in criterion argument', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['=SUMIF(A1:A1, "$1")'], - ['=SUMIF(A1:A1, " $1")'], - ['=SUMIF(A1:A1, "$ 1")'], - ['=SUMIF(A1:A1, "$1 ")'], - ['=SUMIF(A1:A1, "100%")'], - ['=SUMIF(A1:A1, " 100%")'], - ['=SUMIF(A1:A1, "100 %")'], - ['=SUMIF(A1:A1, "100% ")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('A4'))).toEqual(1) - expect(engine.getCellValue(adr('A5'))).toEqual(1) - expect(engine.getCellValue(adr('A6'))).toEqual(1) - expect(engine.getCellValue(adr('A7'))).toEqual(1) - expect(engine.getCellValue(adr('A8'))).toEqual(1) - expect(engine.getCellValue(adr('A9'))).toEqual(1) - }) -}) - -describe('Function SUMIFS - argument validations and combinations', () => { - it('requires odd number of arguments, but at least 3', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIFS(C1, ">0")'], - ['=SUMIFS(C1, ">0", B1, B1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('error when criterion unparsable', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIFS(B1:B2, C1:C2, "> { - const engine = HyperFormula.buildFromArray([ - ['=SUMIFS(B1:C1, B2:D2, ">0")'], - ['=SUMIFS(B1, B2:D2, ">0")'], - ['=SUMIFS(B1:D1, B2, ">0")'], - ['=SUMIFS(B1:D1, B2:D2, ">0", B2:E2, ">0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('error when different height dimension of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIFS(B1:B2, C1:C3, ">0")'], - ['=SUMIFS(B1, C1:C2, ">0")'], - ['=SUMIFS(B1:B2, C1, ">0")'], - ['=SUMIFS(B1:B2, C1:C2, ">0", C1:C3, ">0")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('scalars are treated like singular arrays', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIFS(42, 10, ">1")'], - ['=SUMIFS(42, 0, ">1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('error propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMIFS(4/0, 42, ">1")'], - ['=SUMIFS(0, 4/0, ">1")'], - ['=SUMIFS(0, 42, 4/0)'], - ['=SUMIFS(0, 4/0, FOOBAR())'], - ['=SUMIFS(4/0, FOOBAR(), ">1")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works when arguments are just references', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=SUMIFS(B1, A1, ">1")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - }) - - it('works with range values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '3', '5'], - ['1', '1', '7', '9'], - ['=SUMIFS(MMULT(C1:D2, C1:D2), MMULT(A1:B2, A1:B2), "=2")'], - ['=SUMIFS(MMULT(C1:D2, C1:D2), A1:B2, "=1")'], - ['=SUMIFS(C1:D2, MMULT(A1:B2, A1:B2), "=2")'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(304) - expect(engine.getCellValue(adr('A4'))).toEqual(304) - expect(engine.getCellValue(adr('A5'))).toEqual(24) - }) - - it('works for mixed reference/range arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['2', '3'], - ['=SUMIFS(B1, A1:A1, ">1")'], - ['4', '5'], - ['=SUMIFS(B3:B3, A3, ">1")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(3) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('works when criterion arg is an inline array', () => { - const engine = HyperFormula.buildFromArray([ - [2, 'a'], - [3, 'b'], - ['=SUMIFS(A1:A2, B1:B2, {"a", "b"})'] - ], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('A3'))).toEqual(2) - expect(engine.getCellValue(adr('B3'))).toEqual(3) - }) -}) - -describe('Function SUMIFS - calcultions on more than one criteria', () => { - it('works for more than one criterion/range pair', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '100', '3'], - ['1', '101', '5'], - ['2', '102', '7'], - ['=SUMIFS(C1:C3, A1:A3, ">=1", B1:B3, "<102")'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) -}) - -describe('Function SUMIF - cache recalculation after cruds', () => { - it('recalculates SUMIF if changes in summed range', () => { - const sheet = [ - ['10', '10'], - ['5', '6'], - ['=SUMIF(A2:B2, ">=1", A1:B1)', '0'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), [['1', '3']]) - - expect(engine.getCellValue(adr('A3'))).toEqual(4) - expect(changes.length).toEqual(3) - expectArrayWithSameContent(changes.map((change) => change.newValue), [1, 3, 4]) - }) - - it('recalculates SUMIF if changes in tested range', () => { - const sheet = [ - ['10', '10'], - ['5', '6'], - ['0', '=SUMIF(A1:B1, ">=2", A2:B2)'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), [['1', '3']]) - - expect(engine.getCellValue(adr('B3'))).toEqual(6) - expect(changes.length).toEqual(3) - expectArrayWithSameContent(changes.map((change) => change.newValue), [1, 3, 6]) - }) - - it('recalculates SUMIF if summed range same as tested range', () => { - const sheet = [ - ['10', '10'], - ['0', '=SUMIF(A1:B1, ">=2", A1:B1)'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - expect(engine.getCellValue(adr('B2'))).toEqual(20) - - const changes = engine.setCellContents(adr('A1'), [['1', '3']]) - - expect(engine.getCellValue(adr('B2'))).toEqual(3) - expect(changes.length).toEqual(3) - expectArrayWithSameContent(changes.map((change) => change.newValue), [1, 3, 3]) - }) -}) - -describe('Function SUMIFS - cache recalculation after cruds', () => { - it('recalculates SUMIFS if changes in summed range', () => { - const sheet = [ - ['10', '10'], - ['5', '6'], - ['7', '8'], - ['=SUMIFS(A1:B1, A2:B2, ">=5", A3:B3, ">=7")'], - ] - const engine = HyperFormula.buildFromArray(sheet) - - const changes = engine.setCellContents(adr('A1'), [['1', '3']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(4) - expect(changes.length).toEqual(3) - expectArrayWithSameContent(changes.map((change) => change.newValue), [1, 3, 4]) - }) - - it('recalculates SUMIFS if changes in one of the tested range', () => { - const sheet = [ - ['10', '10'], - ['5', '6'], - ['7', '8'], - ['=SUMIFS(A1:B1, A2:B2, ">=5", A3:B3, ">=7")'], - ] - const engine = HyperFormula.buildFromArray(sheet) - expect(engine.getCellValue(adr('A4'))).toEqual(20) - - const changes = engine.setCellContents(adr('A3'), [['1', '7']]) - - expect(engine.getCellValue(adr('A4'))).toEqual(10) - expect(changes.length).toEqual(3) - expectArrayWithSameContent(changes.map((change) => change.newValue), [1, 7, 10]) - }) -}) diff --git a/test/unit/interpreter/function-sumproduct.spec.ts b/test/unit/interpreter/function-sumproduct.spec.ts deleted file mode 100644 index 08dfe4d43f..0000000000 --- a/test/unit/interpreter/function-sumproduct.spec.ts +++ /dev/null @@ -1,206 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SUMPRODUCT', () => { - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMPRODUCT()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['2', '2'], - ['3', '3'], - ['=SUMPRODUCT(A1:A3,B1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(14) - }) - - it('works for more args', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['2', '2'], - ['3', '3'], - ['=SUMPRODUCT(A1:A3, B1:B3, A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(36) - }) - - it('works for less args', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['2', '2'], - ['3', '3'], - ['=SUMPRODUCT(A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(6) - }) - - it('works with wider ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '3', '1', '3'], - ['2', '4', '2', '4'], - ['=SUMPRODUCT(A1:B2,C1:D2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(30) - }) - - it('works with cached smaller range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '=SUMPRODUCT(A1:A1, B1:B1)'], - ['2', '2', '=SUMPRODUCT(A1:A2, B1:B2)'], - ['3', '3', '=SUMPRODUCT(A1:A3, B1:B3)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('C2'))).toEqual(5) - expect(engine.getCellValue(adr('C3'))).toEqual(14) - }) - - it('sumproduct from scalars', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMPRODUCT(42, 78)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(3276) - }) - - it('use cached value if the same formula used', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['2', '2'], - ['=SUMPRODUCT(A1:A2,B1:B2)'], - ['=SUMPRODUCT(A1:A2,B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('makes a coercion from other values', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', '42'], - ['=SUMPRODUCT(A1,B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(42) - }) - - it('if coercion unsuccessful, it ignores it', () => { - const engine = HyperFormula.buildFromArray([ - ['"foobar"', '42'], - ['=SUMPRODUCT(A1,B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('works even if some string in data', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1'], - ['asdf', 'fdsafdsa'], - ['=SUMPRODUCT(A1:A2,B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(1) - }) - - it('works even if both strings passed', () => { - const engine = HyperFormula.buildFromArray([ - ['asdf', 'fdsafdsa'], - ['=SUMPRODUCT(A1,B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('works even if both booleans passed', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', '=FALSE()'], - ['=SUMPRODUCT(A1,B1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('error if error is somewhere in right value', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '78'], - ['13', '=4/0'], - ['=SUMPRODUCT(A1:A2,B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('error if error is somewhere in left value', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '78'], - ['=3/0', '13'], - ['=SUMPRODUCT(A1:A2,B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('error in left has precedence over error in right', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '78'], - ['=UNKNOWNFUNCTION()', '=3/0'], - ['=SUMPRODUCT(A1:A2,B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('UNKNOWNFUNCTION'))) - }) - - it('error when different size', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '3', '1', '3'], - ['2', '4', '2', '4'], - ['=SUMPRODUCT(A1:B2,C1:C2)'], - ['=SUMPRODUCT(A1:B2,C1:D1)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - it('works with matrices', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3'], - ['=SUMPRODUCT(A1:B1, TRANSPOSE(A1:A2))'], - ]) - expect(engine.getCellValue(adr('A3'))).toEqual(7) - }) - - it('error if mismatched range shape', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ['2'], - ['3'], - ['=SUMPRODUCT(A1:C1,A1:A3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EqualLength)) - }) - - // Inconsistency with Product 1 - it('order of errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '', '=FOOBAR()', '12'], - ['3', '=4/0', '', '13', '14'], - ['=SUMPRODUCT(A1:B2, D1:E2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) -}) diff --git a/test/unit/interpreter/function-sumsq.spec.ts b/test/unit/interpreter/function-sumsq.spec.ts deleted file mode 100644 index a78a996019..0000000000 --- a/test/unit/interpreter/function-sumsq.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('SUMSQ', () => { - it('SUMSQ without args', () => { - const engine = HyperFormula.buildFromArray([['=SUMSQ()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('SUMSQ with args', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMSQ(1, B1)', '2'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(5) - }) - - it('SUMSQ with range args', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '5'], - ['3', '4', '=SUMSQ(A1:B2)'], - ]) - expect(engine.getCellValue(adr('C2'))).toEqual(30) - }) - - it('SUMSQ with using previously cached value', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '=SUMSQ(A1:A1)'], - ['4', '=SUMSQ(A1:A2)'], - ]) - expect(engine.getCellValue(adr('B2'))).toEqual(25) - }) - - it('doesnt do coercions', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['foo'], - ['=TRUE()'], - ['=CONCATENATE("1","0")'], - ['=SUMSQ(A1:A5)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual(5) - }) - - it('range only with empty value', () => { - const engine = HyperFormula.buildFromArray([ - ['', '=SUMSQ(A1:A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('range only with some empty values', () => { - const engine = HyperFormula.buildFromArray([ - ['42', '', '13', '=SUMSQ(A1:C1)'], - ]) - - expect(engine.getCellValue(adr('D1'))).toEqual(1933) - }) - - it('over a range value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=SUMSQ(MMULT(A1:B2, A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(858) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['=FOOBAR()', '4'], - ['=SUMSQ(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-sumx2my2.spec.ts b/test/unit/interpreter/function-sumx2my2.spec.ts deleted file mode 100644 index 980cd08bbc..0000000000 --- a/test/unit/interpreter/function-sumx2my2.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SUMX2MY2', () => { - it('should validate number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2MY2(1)'], - ['=SUMX2MY2(1,2,3)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return correct output', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2MY2(A2:D2, A3:D3)'], - [1, 2, 3, 4], - [5, 4, 2, 1], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(-16) - }) - - it('should validate that ranges are of equal length', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2MY2(A2:F2, A3:E3)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('should propagate errors (from array 1)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2MY2(A2:E2, A3:E3)'], - [1, 2, 3, '=NA()', 5, 6], - [5, 4, 2, 1, 5, 10], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should propagate errors (from array 2)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2MY2(A2:E2, A3:E3)'], - [5, 4, 2, 1, 5, 10], - [1, 2, 3, '=NA()', 5, 6], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should ignore non-number inputs', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2MY2(A2:D2, A3:D3)'], - [null, 2, '\'1', 4], - [5, '\'abcd', 2, true], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/function-sumx2py2.spec.ts b/test/unit/interpreter/function-sumx2py2.spec.ts deleted file mode 100644 index 703d6c6e9f..0000000000 --- a/test/unit/interpreter/function-sumx2py2.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SUMX2PY2', () => { - it('should validate number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2PY2(1)'], - ['=SUMX2PY2(1,2,3)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return correct output', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2PY2(A2:D2, A3:D3)'], - [1, 2, 3, 4], - [5, 4, 2, 1], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(76) - }) - - it('should validate that ranges are of equal length', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2PY2(A2:F2, A3:E3)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('should propagate errors (from array 1)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2PY2(A2:E2, A3:E3)'], - [1, 2, 3, '=NA()', 5, 6], - [5, 4, 2, 1, 5, 10], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should propagate errors (from array 2)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2PY2(A2:E2, A3:E3)'], - [5, 4, 2, 1, 5, 10], - [1, 2, 3, '=NA()', 5, 6], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should ignore non-number inputs', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMX2PY2(A2:D2, A3:D3)'], - [null, 2, '\'1', 4], - [5, '\'abcd', 2, true], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/function-sumxmy2.spec.ts b/test/unit/interpreter/function-sumxmy2.spec.ts deleted file mode 100644 index 564fd0c090..0000000000 --- a/test/unit/interpreter/function-sumxmy2.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SUMXMY2', () => { - it('should validate number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMXMY2(1)'], - ['=SUMXMY2(1,2,3)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return correct output', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMXMY2(A2:D2, A3:D3)'], - [1, 2, 3, 4], - [5, 4, 2, 1], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(30) - }) - - it('should validate that ranges are of equal length', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMXMY2(A2:F2, A3:E3)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('should propagate errors (from array 1)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMXMY2(A2:E2, A3:E3)'], - [1, 2, 3, '=NA()', 5, 6], - [5, 4, 2, 1, 5, 10], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should propagate errors (from array 2)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMXMY2(A2:E2, A3:E3)'], - [5, 4, 2, 1, 5, 10], - [1, 2, 3, '=NA()', 5, 6], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('should ignore non-number inputs', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUMXMY2(A2:D2, A3:D3)'], - [null, 2, '\'1', 4], - [5, '\'abcd', 2, true], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/function-switch.spec.ts b/test/unit/interpreter/function-switch.spec.ts deleted file mode 100644 index ce2ae50f5c..0000000000 --- a/test/unit/interpreter/function-switch.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - SWITCH function', () => { - it('Should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SWITCH(1)', '=SWITCH(2,3)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('Should work with more arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SWITCH(1,2,3)', '=SWITCH(1,2,3,4)', '=SWITCH(1,2,3,4,5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.NoDefault)) - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.NoDefault)) - }) - - it('Should work with precision', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1.0000000001', '3', '1.0000000000001', '5'], - ['=SWITCH(A1,B1,C1,D1,E1)'] - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - }) - - it('Should work with strings', () => { - const engine = HyperFormula.buildFromArray([ - ['abc', '1', '3', 'ABC', '5'], - ['=SWITCH(A1,B1,C1,D1,E1)'] - ], {caseSensitive: false}) - expect(engine.getCellValue(adr('A2'))).toEqual(5) - }) - it('Should fail with error in first argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=SWITCH(1/0,1/0,3,4,5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - it('Should not fail with error in other arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SWITCH(4,1/0,3,4,5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - it('Should pass errors as normal values', () => { - const engine = HyperFormula.buildFromArray([ - ['=SWITCH(4,2,3,4,1/0)', '=SWITCH(1,2,3,4,1/0,5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B1'))).toEqual(5) - }) - it('Should fail with range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SWITCH(1,2,A2:A3,4,5)'] - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - it('passes subtypes', () => { - const engine = HyperFormula.buildFromArray([['=SWITCH(1,1,B1)', '1%']]) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) -}) diff --git a/test/unit/interpreter/function-syd.spec.ts b/test/unit/interpreter/function-syd.spec.ts deleted file mode 100644 index d2ad44eeb3..0000000000 --- a/test/unit/interpreter/function-syd.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function SYD', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=SYD(1,1,1)', '=SYD(1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=SYD(100, 1, 2.1, 2)', '=SYD(100, 1, 2.1, 2.1)', '=SYD(100, 1, 2, 2.1)', '=SYD(100, 1, 2, 2)', ], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(33.4562211981567) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(30.4147465437788) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NUM)) - expect(engine.getCellValue(adr('D1'))).toBeCloseTo(33) - }) -}) diff --git a/test/unit/interpreter/function-t.dist.2t.spec.ts b/test/unit/interpreter/function-t.dist.2t.spec.ts deleted file mode 100644 index 8aa3818214..0000000000 --- a/test/unit/interpreter/function-t.dist.2t.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function T.DIST.2T', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.2T(1)'], - ['=T.DIST.2T(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.2T("foo", 2)'], - ['=T.DIST.2T(1, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.2T(1, 1)'], - ['=T.DIST.2T(3, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0954659662667092, 6) - }) - - it('should truncate input', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.2T(1, 1.9)'], - ['=T.DIST.2T(3, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0954659662667092, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.2T(0, 1)'], - ['=T.DIST.2T(-0.01, 1)'], - ['=T.DIST.2T(1, 0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1, 6) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-t.dist.rt.spec.ts b/test/unit/interpreter/function-t.dist.rt.spec.ts deleted file mode 100644 index 476d91b46d..0000000000 --- a/test/unit/interpreter/function-t.dist.rt.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function T.DIST.RT', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.RT(1)'], - ['=T.DIST.RT(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.RT("foo", 2)'], - ['=T.DIST.RT(1, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.RT(1, 1)'], - ['=T.DIST.RT(3, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.25, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0477329831333546, 6) - }) - - it('should truncate input', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.RT(1, 1.9)'], - ['=T.DIST.RT(3, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.25, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0477329831333546, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST.RT(0, 1)'], - ['=T.DIST.RT(-0.01, 1)'], - ['=T.DIST.RT(1, 0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.50318300828035, 6) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-t.dist.spec.ts b/test/unit/interpreter/function-t.dist.spec.ts deleted file mode 100644 index 347023a421..0000000000 --- a/test/unit/interpreter/function-t.dist.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function T.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST(1, 2)'], - ['=T.DIST(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST("foo", 2, TRUE())'], - ['=T.DIST(1, "baz", TRUE())'], - ['=T.DIST(1, 2, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST(1, 1, TRUE())'], - ['=T.DIST(3, 2, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.75, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.952267016866645, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST(1, 1, FALSE())'], - ['=T.DIST(3, 2, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.159154942198517, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0274101222343421, 6) - }) - - it('should truncate input', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST(1, 1.9, TRUE())'], - ['=T.DIST(3, 2.9, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.75, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.952267016866645, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.DIST(-1, 1, FALSE())'], - ['=T.DIST(1, 0.9, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.159154942198517, 11) - //product #2 returns different error - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-t.inv.2t.spec.ts b/test/unit/interpreter/function-t.inv.2t.spec.ts deleted file mode 100644 index 224bb28a5b..0000000000 --- a/test/unit/interpreter/function-t.inv.2t.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function T.INV.2T', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV.2T(1)'], - ['=T.INV.2T(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV.2T("foo", 2)'], - ['=T.INV.2T(0.5, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV.2T(0.1, 1)'], - ['=T.INV.2T(0.9, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(6.31375151467394, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.142133810903748, 6) - }) - - it('should truncate input', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV.2T(0.1, 1.9)'], - ['=T.INV.2T(0.9, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(6.31375151467394, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.142133810903748, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV.2T(0.01, 1)'], - ['=T.INV.2T(0, 1)'], - ['=T.INV.2T(1, 1)'], - ['=T.INV.2T(1.01, 1)'], - ['=T.INV.2T(0.5, 0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(63.656741162866, 6) - //product #2 returns different error - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqual(0) - //product #2 returns value - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-t.inv.spec.ts b/test/unit/interpreter/function-t.inv.spec.ts deleted file mode 100644 index 4352299e20..0000000000 --- a/test/unit/interpreter/function-t.inv.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function T.INV', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV(1)'], - ['=T.INV(1, 2, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV("foo", 2)'], - ['=T.INV(0.5, "baz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV(0.1, 1)'], - ['=T.INV(0.9, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-3.07768353592299, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.88561804936468, 6) - }) - - it('should truncate input', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV(0.1, 1.9)'], - ['=T.INV(0.9, 2.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-3.07768353592299, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1.88561804936468, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.INV(0.01, 1)'], - ['=T.INV(0, 1)'], - ['=T.INV(0.99, 1)'], - ['=T.INV(1, 1)'], - ['=T.INV(0.5, 0.9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(-31.820515953771, 6) - //product #2 returns different error - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(31.820515953771, 6) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueLarge)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-t.spec.ts b/test/unit/interpreter/function-t.spec.ts deleted file mode 100644 index 5e42b79dfa..0000000000 --- a/test/unit/interpreter/function-t.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function T', () => { - it('should take one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=T()'], - ['=T("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return given text', () => { - const engine = HyperFormula.buildFromArray([ - ['=T("foo")'], - ['=T(B2)', 'bar'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('A2'))).toEqual('bar') - }) - - it('should return empty string if given value is not a text', () => { - const engine = HyperFormula.buildFromArray([ - ['=T(B1)', '=TRUE()'], - ['=T(B2)', 42], - ['=T(B3)', null], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('') - expect(engine.getCellValue(adr('A3'))).toEqual('') - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=T(B1)', '=1/0'], - ['=T(B2)', '=FOO()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOO'))) - }) -}) diff --git a/test/unit/interpreter/function-t.test.spec.ts b/test/unit/interpreter/function-t.test.spec.ts deleted file mode 100644 index 6f0e60dbd3..0000000000 --- a/test/unit/interpreter/function-t.test.spec.ts +++ /dev/null @@ -1,154 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('T.TEST', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.TEST(1, 2, 3)'], - ['=T.TEST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works for mode 1', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10], - [2, 5], - ['=T.TEST(A1:A2, B1:B2, 1, 1)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.1475836177, 6) - }) - - it('works for mode 2', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10], - [2, 5], - ['=T.TEST(A1:A2, B1:B2, 1, 2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.07142857143, 6) - }) - - it('works for mode 3', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10], - [2, 5], - ['=T.TEST(A1:A2, B1:B2, 1, 3)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.1203798536, 6) - }) - - it('works for larger ranges for mode 1', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, 8], - ['=T.TEST(A1:F1, A2:F2, 2, 1)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.741153821738662, 9) - }) - - it('works for larger ranges for mode 2', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, 8], - ['=T.TEST(A1:F1, A2:F2, 2, 2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.8654794555, 9) - }) - - it('works for larger ranges for mode 3', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, 1, 1, 4, 8], - ['=T.TEST(A1:F1, A2:F2, 2, 3)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.8658288672, 9) - }) - - it('validates range length for mode 1', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3], - [2, 5, 1, 1, 4, 8], - ['=T.TEST(A1:E1, A2:F2, 1, 1)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.EqualLength)) - }) - - it('works for distinct length ranges for mode 2', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3], - [2, 5, 1, 1, 4, 8], - ['=T.TEST(A1:E1, A2:F2, 1, 2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.442070764, 6) - }) - - it('works for distinct length ranges for mode 3', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3], - [2, 5, 1, 1, 4, 8], - ['=T.TEST(A1:E1, A2:F2, 1, 3)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.4444544032, 6) - }) - - it('doesnt do coercions, nonnumeric values are skipped for mode 1', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3], - [2, 5, null, 1, 4, 8], - ['=T.TEST(A1:E1, A2:F2, 1, 1)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.3298741207, 9) - }) - - it('doesnt do coercions, nonnumeric values are skipped for mode 2', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, null, 1, 4, 8], - ['=T.TEST(A1:F1, A2:F2, 1, 2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.4684423056, 9) - }) - - it('doesnt do coercions, nonnumeric values are skipped for mode 3', () => { - const engine = HyperFormula.buildFromArray([ - [1, 10, 1, 1, 3, 7], - [2, 5, null, 1, 4, 8], - ['=T.TEST(A1:F1, A2:F2, 1, 3)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.4674248166, 9) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=NA()', '50'], - ['3', '30'], - ['=T.TEST(A1:A3, B1:B3, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA)) - }) - - it('error when not enough data', () => { - const engine = HyperFormula.buildFromArray([ - ['=T.TEST(1, 2, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - }) -}) diff --git a/test/unit/interpreter/function-tan.spec.ts b/test/unit/interpreter/function-tan.spec.ts deleted file mode 100644 index 2ac77bed86..0000000000 --- a/test/unit/interpreter/function-tan.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TAN', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=TAN(0)', '=TAN(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.546302489843791) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=TAN("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=TAN()', '=TAN(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=TAN(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-1.5574077246549) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=TAN(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-tanh.spec.ts b/test/unit/interpreter/function-tanh.spec.ts deleted file mode 100644 index 59396f8579..0000000000 --- a/test/unit/interpreter/function-tanh.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TANH', () => { - it('happy path', () => { - const engine = HyperFormula.buildFromArray([['=TANH(0)', '=TANH(0.5)']]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(0.46211715726001) - }) - - it('when value not numeric', () => { - const engine = HyperFormula.buildFromArray([['=TANH("foo")']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([['=TANH()', '=TANH(1,-1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('use number coercion', () => { - const engine = HyperFormula.buildFromArray([ - ['="-1"', '=TANH(A1)'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(-0.761594155955765) - }) - - it('errors propagation', () => { - const engine = HyperFormula.buildFromArray([ - ['=TANH(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-tbilleq.spec.ts b/test/unit/interpreter/function-tbilleq.spec.ts deleted file mode 100644 index b613d6032b..0000000000 --- a/test/unit/interpreter/function-tbilleq.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TBILLEQ', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TBILLEQ(1,1)', '=TBILLEQ(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=TBILLEQ(0, 100, 0.1)'], - ['=TBILLEQ(0, 360, 0.1)', '=TBILLEQ(0, 183, 0.1)', ], - ['=TBILLEQ(0, 180, 1.9)', '=TBILLEQ(0, 180, 2)', '=TBILLEQ(0, 180, 2.1)', ], - ['=TBILLEQ("1/2/2000", "31/1/2001", 0.1)', '=TBILLEQ(0, 365, 0.1)', ], - ['=TBILLEQ("28/2/2003", "29/2/2004", 0.1)'], - ['=TBILLEQ(2, 2.1, 0.1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.104285714285714, 6) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - //inconsistency with products #1 & #2 - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.112654320987654, 6) - //inconsistency with products #1 & #2 - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(0.106818846941762, 6) - //inconsistency with product #1 (returns #NUM!) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(38.5277777777778, 6) - //inconsistency with product #1 (returns #NUM!) - expect(engine.getCellValue(adr('B3'))).toEqual(0) - expect(engine.getCellValue(adr('C3'))).toEqualError(detailedError(ErrorType.NUM)) - //inconsistency with products #1 & #2 - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(0.112828438948995, 6) - //inconsistency with products #1 & #2 - expect(engine.getCellValue(adr('B4'))).toBeCloseTo(0.112828438948995, 6) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM)) - }) -}) diff --git a/test/unit/interpreter/function-tbillprice.spec.ts b/test/unit/interpreter/function-tbillprice.spec.ts deleted file mode 100644 index 08b0d49109..0000000000 --- a/test/unit/interpreter/function-tbillprice.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TBILLPRICE', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TBILLPRICE(1,1)', '=TBILLPRICE(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=TBILLPRICE(0, 100, 0.1)'], - ['=TBILLPRICE(0, 360, 0.1)', '=TBILLPRICE(0, 183, 0.1)', ], - ['=TBILLPRICE(0, 180, 1.9)', '=TBILLPRICE(0, 180, 2)', '=TBILLPRICE(0, 180, 2.1)', ], - ['=TBILLPRICE("1/2/2000", "31/1/2001", 0.1)', '=TBILLPRICE(0, 365, 0.1)', ], - ['=TBILLPRICE("28/2/2003", "29/2/2004", 0.1)'], - ['=TBILLPRICE(2, 2.1, 0.1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(97.2222222222222, 6) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValue(adr('A2'))).toEqual(90) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(94.9166666666667, 6) - //inconsistency with product #1 (returns #NUM!) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - //inconsistency with product #1 (returns #NUM!) - expect(engine.getCellValue(adr('B3'))).toEqual(0) - expect(engine.getCellValue(adr('C3'))).toEqualError(detailedError(ErrorType.NUM)) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(89.8611111111111, 6) - expect(engine.getCellValue(adr('B4'))).toBeCloseTo(89.8611111111111, 6) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM)) - }) -}) diff --git a/test/unit/interpreter/function-tbillyield.spec.ts b/test/unit/interpreter/function-tbillyield.spec.ts deleted file mode 100644 index 2b3b781cd1..0000000000 --- a/test/unit/interpreter/function-tbillyield.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellValueDetailedType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TBILLYIELD', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TBILLYIELD(1,1)', '=TBILLYIELD(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate the correct value with correct arguments and defaults', () => { - const engine = HyperFormula.buildFromArray([ - ['=TBILLYIELD(0, 100, 10)'], - ['=TBILLYIELD(0, 360, 10)', '=TBILLYIELD(0, 183, 10)', ], - ['=TBILLYIELD(0, 180, 10)', '=TBILLYIELD(0, 180, 100)', '=TBILLYIELD(0, 180, 110)', ], - ['=TBILLYIELD("1/2/2000", "31/1/2001", 10)', '=TBILLYIELD(0, 365, 10)', ], - ['=TBILLYIELD("28/2/2003", "29/2/2004", 10)'], - ['=TBILLYIELD(2, 2.1, 10)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(32.4, 6) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValue(adr('A2'))).toEqual(9) - expect(engine.getCellValue(adr('B2'))).toBeCloseTo(17.7049180327869, 6) - expect(engine.getCellValue(adr('A3'))).toEqual(18) - expect(engine.getCellValue(adr('B3'))).toEqual(0) - expect(engine.getCellValue(adr('C3'))).toBeCloseTo(-0.181818181818182, 6) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(8.87671232876712, 6) - expect(engine.getCellValue(adr('B4'))).toBeCloseTo(8.87671232876712, 6) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM)) - }) -}) diff --git a/test/unit/interpreter/function-tdist.spec.ts b/test/unit/interpreter/function-tdist.spec.ts deleted file mode 100644 index 7abe1193cd..0000000000 --- a/test/unit/interpreter/function-tdist.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TDIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TDIST(1, 1)'], - ['=TDIST(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=TDIST("foo", 2, 3)'], - ['=TDIST(1, "baz", 3)'], - ['=TDIST(1, 2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work as T.DIST.RT', () => { - const engine = HyperFormula.buildFromArray([ - ['=TDIST(1, 1, 1)'], - ['=TDIST(3, 2, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.25, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0477329831333546, 6) - }) - - it('should work as T.DIST.2T', () => { - const engine = HyperFormula.buildFromArray([ - ['=TDIST(1, 1, 2)'], - ['=TDIST(3, 2, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0954659662667092, 6) - }) - - it('should truncate input', () => { - const engine = HyperFormula.buildFromArray([ - ['=TDIST(1, 1.9, 2)'], - ['=TDIST(3, 2.9, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0954659662667092, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=TDIST(0, 1, 1)'], - ['=TDIST(0, 1, 2)'], - ['=TDIST(-0.01, 1, 1)'], - ['=TDIST(-0.01, 1, 2)'], - ['=TDIST(1, 0.9, 1)'], - ['=TDIST(1, 0.9, 2)'], - ['=TDIST(0, 1, 1.5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1, 6) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - //product #2 returns value - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.IntegerExpected)) - }) -}) diff --git a/test/unit/interpreter/function-text.spec.ts b/test/unit/interpreter/function-text.spec.ts deleted file mode 100644 index 63719cbd7b..0000000000 --- a/test/unit/interpreter/function-text.spec.ts +++ /dev/null @@ -1,305 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src' -import {SimpleDateTime} from '../../../src/DateTimeHelper' -import {ErrorMessage} from '../../../src/error-message' -import {defaultStringifyDateTime} from '../../../src/format/format' -import {Maybe} from '../../../src/Maybe' -import {adr, detailedError} from '../testUtils' - -describe('TEXT()', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([[ - '2', - '=TEXT(A1, "mm/dd/yyyy")', - ]]) - - expect(engine.getCellValue(adr('B1'))).toEqual('01/01/1900') - }) - - it('wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TEXT(42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('wrong format argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=TEXT(2, 42)'], - ['=TEXT(2, 0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('42') - expect(engine.getCellValue(adr('A2'))).toEqual('2') - }) - - it('wrong date argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=TEXT(TRUE(), "mm/dd/yyyy")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('12/31/1899') - }) - - it('day formats', () => { - const engine = HyperFormula.buildFromArray([[ - '=DATE(2018, 8, 8)', - '=TEXT(A1, "d d")', - '=TEXT(A1, "dd DD")', - ]]) - - expect(engine.getCellValue(adr('B1'))).toEqual('8 8') - expect(engine.getCellValue(adr('C1'))).toEqual('08 08') - }) - - it('month formats', () => { - const engine = HyperFormula.buildFromArray([[ - '=DATE(2018, 8, 8)', - '=TEXT(A1, "m M")', - '=TEXT(A1, "mm MM")', - ]]) - - expect(engine.getCellValue(adr('B1'))).toEqual('8 0') //heuristic - repeated month is minutes - expect(engine.getCellValue(adr('C1'))).toEqual('08 00') //heuristic - repeated month is minutes - }) - - it('year formats', () => { - const engine = HyperFormula.buildFromArray([[ - '=DATE(2018, 8, 8)', - '=TEXT(A1, "yy YY")', - '=TEXT(A1, "yyyy YYYY")', - ]]) - - expect(engine.getCellValue(adr('B1'))).toEqual('18 18') - expect(engine.getCellValue(adr('C1'))).toEqual('2018 2018') - }) - - it('12 hours', () => { - const engine = HyperFormula.buildFromArray([ - [ - '8/8/2018 14:00', - '=TEXT(A1, "hh:mm A/P")', - ], - [ - '8/8/2018 00:30', - '=TEXT(A2, "hh:mm AM/PM")', - ], - ['8/8/2018 00:30', '=TEXT(A3, "hh:mm am/pm")'], - [ - '8/8/2018 00:30', - '=TEXT(A4, "hh:mm a/p")', - ] - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('02:00 P') - expect(engine.getCellValue(adr('B2'))).toEqual('12:30 AM') - expect(engine.getCellValue(adr('B3'))).toEqual('12:30 am') - expect(engine.getCellValue(adr('B4'))).toEqual('12:30 a') - }) - - it('24 hours', () => { - const engine = HyperFormula.buildFromArray([ - [ - '8/8/2018 13:59', - '=TEXT(A1, "HH:mm")', - ] - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('13:59') - }) - - it('padding', () => { - const engine = HyperFormula.buildFromArray([ - [ - '8/8/2018 01:01:01', '=TEXT(A1, "H:m:s")', - ], - [ - '8/8/2018 01:11:11', '=TEXT(A2, "H:m:s")', - ] - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('1:1:1') - expect(engine.getCellValue(adr('B2'))).toEqual('1:11:11') - }) - - it('fractions of seconds', () => { - const engine = HyperFormula.buildFromArray([ - [ - '0.0000011574074074074074', '=TEXT(A1, "hh:mm:ss.ss")', - ], - ['0.000001', '=TEXT(A2, "hh:mm:ss.sss")'] - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('00:00:00.1') - expect(engine.getCellValue(adr('B2'))).toEqual('00:00:00.086') - }) - - it('distinguishes between months and minutes - not supported', () => { - const engine = HyperFormula.buildFromArray([[ - '=DATE(2018, 8, 8)', - '=TEXT(A1, "mm")', - '=TEXT(A1, "HH:mm")', - '=TEXT(A1, "H:m")', - ]]) - expect(engine.getCellValue(adr('B1'))).toEqual('08') - expect(engine.getCellValue(adr('C1'))).toEqual('00:00') - expect(engine.getCellValue(adr('D1'))).toEqual('0:0') - }) - - it('works for number format', () => { - const engine = HyperFormula.buildFromArray([ - ['12.45'], - ['=TEXT(A1, "###.###")'], - ['=TEXT(A1, "000.000")'], - ['=TEXT(A1, "$000.00")'], - ['=TEXT(A1, "$#.000")'], - ['=TEXT(A1, "$###.000")'], - ['=TEXT(A1, "000.00.00$")'], - ['=TEXT(A1, "###.##.##$")'], - ['=TEXT(A1, "$###,##0.00")'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('12.45') - expect(engine.getCellValue(adr('A3'))).toEqual('012.450') - expect(engine.getCellValue(adr('A4'))).toEqual('$012.45') - expect(engine.getCellValue(adr('A5'))).toEqual('$12.450') - expect(engine.getCellValue(adr('A6'))).toEqual('$12.450') - expect(engine.getCellValue(adr('A7'))).toEqual('012.45.00$') - expect(engine.getCellValue(adr('A8'))).toEqual('12.45.##$') - expect(engine.getCellValue(adr('A9'))).toEqual('$12,##0.00') - }) - - it('works with currency format "$#.00"', () => { - const engine = HyperFormula.buildFromArray([ - ['=TEXT(0.5, "$#.00")'], - ['=TEXT(10, "$#.00")'], - ['=TEXT(100, "$#.00")'], - ['=TEXT(1000, "$#.00")'], - ['=TEXT(10000, "$#.00")'], - ['=TEXT(100000, "$#.00")'], - ['=TEXT(1000000, "$#.00")'], - ['=TEXT(10000000, "$#.00")'], - ['=TEXT(10000000.99, "$#.00")'], - ['=TEXT(10000000.99999, "$#.00")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('$0.50') - expect(engine.getCellValue(adr('A2'))).toEqual('$10.00') - expect(engine.getCellValue(adr('A3'))).toEqual('$100.00') - expect(engine.getCellValue(adr('A4'))).toEqual('$1000.00') - expect(engine.getCellValue(adr('A5'))).toEqual('$10000.00') - expect(engine.getCellValue(adr('A6'))).toEqual('$100000.00') - expect(engine.getCellValue(adr('A7'))).toEqual('$1000000.00') - expect(engine.getCellValue(adr('A8'))).toEqual('$10000000.00') - expect(engine.getCellValue(adr('A9'))).toEqual('$10000000.99') - expect(engine.getCellValue(adr('A10'))).toEqual('$10000001.00') - }) - - it('date and time format', () => { - const engine = HyperFormula.buildFromArray([ - ['1.100', '=TEXT(A1, "yyyy-mm-dd hh:mm:ss")'], - ['1.222', '=TEXT(A2, "yyyy-mm-dd hh:mm:ss")'], - ['0.99999', '=TEXT(A3, "yyyy-mm-dd hh:mm:ss")'], - ['0.999999', '=TEXT(A4, "yyyy-mm-dd hh:mm:ss")'], - ['0.9999999', '=TEXT(A5, "yyyy-mm-dd hh:mm:ss")'], - ['0.99999999', '=TEXT(A6, "yyyy-mm-dd hh:mm:ss")'], - ['0.999999999', '=TEXT(A7, "yyyy-mm-dd hh:mm:ss")'], - ['0.9999999999', '=TEXT(A8, "yyyy-mm-dd hh:mm:ss")'], - ['0.99999999999', '=TEXT(A9, "yyyy-mm-dd hh:mm:ss")'], - ['0.999999999999', '=TEXT(A10, "yyyy-mm-dd hh:mm:ss")'] - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual('1899-12-31 02:24:00') - expect(engine.getCellValue(adr('B2'))).toEqual('1899-12-31 05:19:40') - expect(engine.getCellValue(adr('B3'))).toEqual('1899-12-30 23:59:59') - expect(engine.getCellValue(adr('B4'))).toEqual('1899-12-30 23:59:59') - expect(engine.getCellValue(adr('B5'))).toEqual('1899-12-30 23:59:59') - expect(engine.getCellValue(adr('B6'))).toEqual('1899-12-30 23:59:59') - expect(engine.getCellValue(adr('B7'))).toEqual('1899-12-30 23:59:59') - expect(engine.getCellValue(adr('B8'))).toEqual('1899-12-30 23:59:59') - expect(engine.getCellValue(adr('B9'))).toEqual('1899-12-31 00:00:00') - expect(engine.getCellValue(adr('B10'))).toEqual('1899-12-31 00:00:00') - }) - - it('correct rounding', () => { - const engine = HyperFormula.buildFromArray([ - ['0.9999999999', '=TEXT(A1, "yyyy-mm-dd hh:mm:ss.sssss")'], - ['0.9999999999', '=TEXT(A2, "yyyy-mm-dd hh:mm:ss.ssss")'], - ['0.9999999999', '=TEXT(A3, "yyyy-mm-dd hh:mm:ss.sss")'], - ['0.9999999999', '=TEXT(A4, "yyyy-mm-dd hh:mm:ss.ss")'], - ['0.9999999999', '=TEXT(A5, "yyyy-mm-dd hh:mm:ss.s")'], - ['0.9999999999', '=TEXT(A6, "yyyy-mm-dd hh:mm:ss")'], - ['0.9999999999', '=TEXT(A7, "yyyy-mm-dd hh:mm")'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual('1899-12-30 23:59:59.99999') - expect(engine.getCellValue(adr('B2'))).toEqual('1899-12-30 23:59:59.9999') - expect(engine.getCellValue(adr('B3'))).toEqual('1899-12-30 23:59:59.999') - expect(engine.getCellValue(adr('B4'))).toEqual('1899-12-30 23:59:59.99') - expect(engine.getCellValue(adr('B5'))).toEqual('1899-12-30 23:59:59.9') - expect(engine.getCellValue(adr('B6'))).toEqual('1899-12-30 23:59:59') - expect(engine.getCellValue(adr('B7'))).toEqual('1899-12-30 23:59') - }) -}) - -describe('time duration', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['0.1', '=TEXT(A1, "[hh]:mm:ss")'], - ['1.1', '=TEXT(A2, "[hh]:mm:ss")', ], - ['0.1', '=TEXT(A3, "[mm]:ss")', ], - ['1.1', '=TEXT(A4, "[mm]:ss")', ], - ['1.1', '=TEXT(A5, "[hh]:m:ss")', ], - ['0.1111', '=TEXT(A6, "[mm]:ss.ss")', ], - ['0.1111', '=TEXT(A7, "[mm]:ss.00")', ], - ['0.1111', '=TEXT(A8, "hh:[mm]:s")', ], - ['0.1111', '=TEXT(A9, "h:[mm]")', ], - ['0.1111', '=TEXT(A10, "abc")', ], - ]) - expect(engine.getCellValue(adr('B1'))).toEqual('02:24:00') - expect(engine.getCellValue(adr('B2'))).toEqual('26:24:00') - expect(engine.getCellValue(adr('B3'))).toEqual('144:00') - expect(engine.getCellValue(adr('B4'))).toEqual('1584:00') - expect(engine.getCellValue(adr('B5'))).toEqual('26:24:00') - expect(engine.getCellValue(adr('B6'))).toEqual('159:59.04') - expect(engine.getCellValue(adr('B7'))).toEqual('159:59.04') - expect(engine.getCellValue(adr('B8'))).toEqual('02:39:59') - expect(engine.getCellValue(adr('B9'))).toEqual('2:39') - expect(engine.getCellValue(adr('B10'))).toEqual('abc') - }) -}) - -describe('Custom date printing', () => { - function customPrintDate(date: SimpleDateTime, dateFormat: string): Maybe { - const str = defaultStringifyDateTime(date, dateFormat) - if (str === undefined) { - return undefined - } else { - return 'fancy ' + str + ' fancy' - } - } - - it('works', () => { - const engine = HyperFormula.buildFromArray([[ - '2', - '=TEXT(A1, "mm/dd/yyyy")', - ]], {stringifyDateTime: customPrintDate}) - - expect(engine.getCellValue(adr('B1'))).toEqual('fancy 01/01/1900 fancy') - }) - - it('no effect for number format', () => { - const engine = HyperFormula.buildFromArray([[ - '12.45', - '=TEXT(A1, "###.###")', - '=TEXT(A1, "000.000")', - ]], {stringifyDateTime: customPrintDate}) - - expect(engine.getCellValue(adr('B1'))).toEqual('12.45') - expect(engine.getCellValue(adr('C1'))).toEqual('012.450') - }) - - it('date printing, month and minutes', () => { - const engine = HyperFormula.buildFromArray([['1.1', '=TEXT(A1, "mm-dd mm:ss.sssss")'], - ['1.222', '=TEXT(A2, "mm-dd mm:ss.sssss")']]) - expect(engine.getCellValue(adr('B1'))).toEqual('12-31 24:00') - expect(engine.getCellValue(adr('B2'))).toEqual('12-31 19:40.79999') - }) -}) diff --git a/test/unit/interpreter/function-time.spec.ts b/test/unit/interpreter/function-time.spec.ts deleted file mode 100644 index 0a7340d6f0..0000000000 --- a/test/unit/interpreter/function-time.spec.ts +++ /dev/null @@ -1,114 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError, timeNumberToString} from '../testUtils' - -describe('Function TIME', () => { - it('with 3 numerical arguments', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME(0, 0, 0)', '=TIME(21, 0, 54)', '=TIME(3, 10, 24)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(timeNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('00:00:00') - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValue(adr('B1'))).toEqual(0.875625) - expect(timeNumberToString(engine.getCellValue(adr('B1')), config)).toEqual('21:00:54') - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(0.132222222222222) - expect(timeNumberToString(engine.getCellValue(adr('C1')), config)).toEqual('03:10:24') - }) - - it('truncation', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME(0.9, 0, 0)', '=TIME(21, 0.5, 54)', '=TIME(3, 10, 24.99)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(timeNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('00:00:00') - expect(engine.getCellValue(adr('B1'))).toEqual(0.875625) - expect(timeNumberToString(engine.getCellValue(adr('B1')), config)).toEqual('21:00:54') - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(0.132222222222222) - expect(timeNumberToString(engine.getCellValue(adr('C1')), config)).toEqual('03:10:24') - }) - - it('rollover', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME(24, 0, 0)', '=TIME(19, 120, 54)', '=TIME(0, 189, 84)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(timeNumberToString(engine.getCellValue(adr('A1')), config)).toEqual('00:00:00') - expect(engine.getCellValue(adr('B1'))).toEqual(0.875625) - expect(timeNumberToString(engine.getCellValue(adr('B1')), config)).toEqual('21:00:54') - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(0.132222222222222) - expect(timeNumberToString(engine.getCellValue(adr('C1')), config)).toEqual('03:10:24') - }) - - it('negative', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME(-1, 59, 0)', '=TIME(0, -1, 59)', '=TIME(0, 1, -61)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NegativeTime)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NegativeTime)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NegativeTime)) - }) - - it('fractions', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME(0, 0.9, 0)', '=TIME(0, 0, -0.9)', '=TIME(0.9, 0, 0)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - - it('number of arguments', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME(0, 1)'], - ['=TIME(0, 1, 1, 1)'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with incoercible argument', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME("foo", 1, 1)'], - ['=TIME(0, "foo", 1)'], - ['=TIME(0, 1, "foo")'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('with coercible argument', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['="0"', '=TRUE()'], - ['=TIME(A1, 1, 1)'], - ['=TIME(0, B1, 1)'], - ['=TIME(0, 1, B1)'], - ], config) - expect(timeNumberToString(engine.getCellValue(adr('A2')), config)).toEqual('00:01:01') - expect(timeNumberToString(engine.getCellValue(adr('A3')), config)).toEqual('00:01:01') - expect(timeNumberToString(engine.getCellValue(adr('A4')), config)).toEqual('00:01:01') - }) - - it('precedence of errors', () => { - const config = new Config() - const engine = HyperFormula.buildFromArray([ - ['=TIME(FOOBAR(), 4/0, 1)'], - ['=TIME(0, FOOBAR(), 4/0)'], - ['=TIME(0, 1, FOOBAR())'], - ], config) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) -}) diff --git a/test/unit/interpreter/function-timevalue.spec.ts b/test/unit/interpreter/function-timevalue.spec.ts deleted file mode 100644 index 856e4374cf..0000000000 --- a/test/unit/interpreter/function-timevalue.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TIMEVALUE', () => { - it('with wrong arguments', () => { - const engine = HyperFormula.buildFromArray([['=TIMEVALUE("foo")', '=TIMEVALUE(1)', '=TIMEVALUE(1, 2)', '=TIMEVALUE()']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IncorrectDateTime)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.IncorrectDateTime)) - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=TIMEVALUE("3:00pm")', '=TIMEVALUE("15:00")', '=TIMEVALUE("21:00:00")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.625) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValue(adr('B1'))).toEqual(0.625) - expect(engine.getCellValue(adr('C1'))).toEqual(0.875) - }) - - it('ignores date', () => { - const engine = HyperFormula.buildFromArray([['=TIMEVALUE("3:00pm")', '=TIMEVALUE("31/12/2018 3:00pm")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.625) - expect(engine.getCellValue(adr('B1'))).toEqual(0.625) - }) - - it('rollover', () => { - const engine = HyperFormula.buildFromArray([['=TIMEVALUE("24:00")', '=TIMEVALUE("31/12/2018 24:00")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=TIMEVALUE(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should return NUMBER_TIME', () => { - const engine = HyperFormula.buildFromArray([ - ['=TIMEVALUE("14:31")'], - ]) - - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_TIME) - }) -}) diff --git a/test/unit/interpreter/function-today.spec.ts b/test/unit/interpreter/function-today.spec.ts deleted file mode 100644 index 6ac6e10df2..0000000000 --- a/test/unit/interpreter/function-today.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {HyperFormula} from '../../../src' -import {CellValueDetailedType, ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - function TODAY', () => { - let originalNow: () => number - - beforeEach(() => { - originalNow = Date.now - let cnt = 20 - Date.now = () => { - cnt += 1 - return Date.parse(`1985-08-16T03:45:${cnt}`) - } - }) - - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=TODAY()'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(31275) - expect(engine.getCellValueDetailedType(adr('A1'))).toBe(CellValueDetailedType.NUMBER_DATE) - }) - - it('works #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEAR(TODAY())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1985) - }) - - it('works #3', () => { - const engine = HyperFormula.buildFromArray([ - ['=MONTH(TODAY())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(8) - }) - - it('works #4', () => { - const engine = HyperFormula.buildFromArray([ - ['=DAY(TODAY())'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(16) - }) - - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TODAY(42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - afterEach(() => { - Date.now = originalNow - }) -}) diff --git a/test/unit/interpreter/function-trim.spec.ts b/test/unit/interpreter/function-trim.spec.ts deleted file mode 100644 index e49c0e45dd..0000000000 --- a/test/unit/interpreter/function-trim.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TRIM', () => { - it('should return N/A when number of arguments is incorrect', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRIM()'], - ['=TRIM("foo", "bar")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRIM(" foo")'], - ['=TRIM("foo ")'], - ['=TRIM(" foo ")'], - ['=TRIM(" f o o ")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('foo') - expect(engine.getCellValue(adr('A2'))).toEqual('foo') - expect(engine.getCellValue(adr('A3'))).toEqual('foo') - expect(engine.getCellValue(adr('A4'))).toEqual('f o o') - }) - - it('should coerce other types to string', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRIM(1)'], - ['=TRIM(5+5)'], - ['=TRIM(TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - expect(engine.getCellValue(adr('A2'))).toEqual('10') - expect(engine.getCellValue(adr('A3'))).toEqual('TRUE') - }) -}) diff --git a/test/unit/interpreter/function-true.spec.ts b/test/unit/interpreter/function-true.spec.ts deleted file mode 100644 index 2c3b35d6c2..0000000000 --- a/test/unit/interpreter/function-true.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function TRUE', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([['=TRUE()']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(true) - }) - - it('is 0-arity', () => { - const engine = HyperFormula.buildFromArray([['=TRUE(1)']]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) -}) diff --git a/test/unit/interpreter/function-unichar.spec.ts b/test/unit/interpreter/function-unichar.spec.ts deleted file mode 100644 index 098e72129e..0000000000 --- a/test/unit/interpreter/function-unichar.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function UNICHAR', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICHAR()'], - ['=UNICHAR(1, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICHAR("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICHAR(1)'], - ['=UNICHAR(33)'], - ['=UNICHAR(65)'], - ['=UNICHAR(90)'], - ['=UNICHAR(209)'], - ['=UNICHAR(255)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('!') - expect(engine.getCellValue(adr('A3'))).toEqual('A') - expect(engine.getCellValue(adr('A4'))).toEqual('Z') - expect(engine.getCellValue(adr('A5'))).toEqual('Ñ') - expect(engine.getCellValue(adr('A6'))).toEqual('ÿ') - }) - - it('should round down floats', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICHAR(42)'], - ['=UNICHAR(42.2)'], - ['=UNICHAR(42.8)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('*') - expect(engine.getCellValue(adr('A2'))).toEqual('*') - expect(engine.getCellValue(adr('A3'))).toEqual('*') - }) - - it('should work only for values from 1 to 1114111 truncating decimal part', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICHAR(0)'], - ['=UNICHAR(0.5)'], - ['=UNICHAR(1)'], - ['=UNICHAR(256)'], - ['=UNICHAR(1114111)'], - ['=UNICHAR(1114111.5)'], - ['=UNICHAR(1114112)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds)) - expect(engine.getCellValue(adr('A3'))).toEqual('') - expect(engine.getCellValue(adr('A4'))).toEqual('Ā') - expect(engine.getCellValue(adr('A5'))).toEqual('􏿿') - expect(engine.getCellValue(adr('A6'))).toEqual('􏿿') - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.CharacterCodeBounds)) - }) -}) diff --git a/test/unit/interpreter/function-unicode.spec.ts b/test/unit/interpreter/function-unicode.spec.ts deleted file mode 100644 index 73ab450df2..0000000000 --- a/test/unit/interpreter/function-unicode.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import {CellValueType, ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function UNICODE', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICODE()'], - ['=UNICODE("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for empty strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICODE("")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.EmptyString)) - }) - - it('should work for single chars', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICODE("")'], - ['=UNICODE("!")'], - ['=UNICODE("A")'], - ['=UNICODE("Z")'], - ['=UNICODE("Ñ")'], - ['=UNICODE("ÿ")'], - ['=UNICODE(TRUE())'], - ['=UNICODE("€")'], - ['=UNICODE("􏿿")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(33) - expect(engine.getCellValue(adr('A3'))).toEqual(65) - expect(engine.getCellValue(adr('A4'))).toEqual(90) - expect(engine.getCellValue(adr('A5'))).toEqual(209) - expect(engine.getCellValue(adr('A6'))).toEqual(255) - expect(engine.getCellValue(adr('A7'))).toEqual(84) - expect(engine.getCellValue(adr('A8'))).toEqual(8364) - expect(engine.getCellValue(adr('A9'))).toEqual(1114111) - }) - - it('should return code of first character', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICODE("Abar")'], - ['=UNICODE("Ñbaz")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(65) - expect(engine.getCellValue(adr('A2'))).toEqual(209) - }) - - it('should return number', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICODE("foo")'] - ]) - - expect(engine.getCellValueType(adr('A1'))).toEqual(CellValueType.NUMBER) - }) - - it('should be identity when composed with UNICHAR', () => { - const engine = HyperFormula.buildFromArray([ - ['=UNICODE(UNICHAR(1))'], - ['=UNICODE(UNICHAR(128))'], - ['=UNICODE(UNICHAR(256))'], - ['=UNICODE(UNICHAR(8364))'], - ['=UNICODE(UNICHAR(1114111))'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqual(128) - expect(engine.getCellValue(adr('A3'))).toEqual(256) - expect(engine.getCellValue(adr('A4'))).toEqual(8364) - expect(engine.getCellValue(adr('A5'))).toEqual(1114111) - }) -}) diff --git a/test/unit/interpreter/function-upper.spec.ts b/test/unit/interpreter/function-upper.spec.ts deleted file mode 100644 index 7bd1191bdb..0000000000 --- a/test/unit/interpreter/function-upper.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function UPPER', () => { - it('should take one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=UPPER()'], - ['=UPPER("foo", "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should convert text to uppercase', () => { - const engine = HyperFormula.buildFromArray([ - ['=UPPER("")'], - ['=UPPER(B1)'], - ['=UPPER("FOO")'], - ['=UPPER("foo")'], - ['=UPPER("bAr")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('') - expect(engine.getCellValue(adr('A2'))).toEqual('') - expect(engine.getCellValue(adr('A3'))).toEqual('FOO') - expect(engine.getCellValue(adr('A4'))).toEqual('FOO') - expect(engine.getCellValue(adr('A5'))).toEqual('BAR') - }) - - it('should coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=UPPER(TRUE())'], - ['=UPPER(0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('TRUE') - expect(engine.getCellValue(adr('A2'))).toEqual('0') - }) -}) diff --git a/test/unit/interpreter/function-var.p.spec.ts b/test/unit/interpreter/function-var.p.spec.ts deleted file mode 100644 index b02eb0c04c..0000000000 --- a/test/unit/interpreter/function-var.p.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function VAR.P', () => { - it('should take at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.P()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate variance (population)', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.P(2, 3)'], - ['=VAR.P(1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.25) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.P(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.95918367346939, 6) //inconsistency with product #1 - }) - - it('should ignore non-numeric values in ranges, including ignoring logical values and text representation of numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.P(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.666666666666667, 6) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.P(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-var.s.spec.ts b/test/unit/interpreter/function-var.s.spec.ts deleted file mode 100644 index 5f61666f76..0000000000 --- a/test/unit/interpreter/function-var.s.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function VAR.S', () => { - it('should take at least two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.S()'], - ['=VAR.S(1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should calculate variance (sample)', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.S(2, 3)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.5) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.S(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.28571428571429, 6) //inconsistency with product #1 - }) - - it('should ignore non-numeric values in ranges, including ignoring logical values and text representation of numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.S(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=VAR.S(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-vara.spec.ts b/test/unit/interpreter/function-vara.spec.ts deleted file mode 100644 index e338cec370..0000000000 --- a/test/unit/interpreter/function-vara.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function VARA', () => { - it('should take at least two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARA()'], - ['=VARA(1)'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('should calculate variance (sample)', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARA(2, 3)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.5, 6) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARA(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.28571428571429) - }) - - it('should evaluate TRUE to 1, FALSE to 0 and text to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARA(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.61904761904762) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARA(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-varpa.spec.ts b/test/unit/interpreter/function-varpa.spec.ts deleted file mode 100644 index 77b8d3d734..0000000000 --- a/test/unit/interpreter/function-varpa.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function VARPA', () => { - it('should take at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARPA()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should calculate variance (population)', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARPA(2, 3)'], - ['=VARPA(1)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(0.25) - expect(engine.getCellValue(adr('A2'))).toEqual(0) - }) - - it('should coerce explicit argument to numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARPA(2, 3, 4, TRUE(), FALSE(), "1",)'], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1.95918367346939, 6) - }) - - it('should evaluate TRUE to 1, FALSE to 0 and text to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARPA(B1:I1)', 2, 3, 4, true, false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.24489795918367, 6) - }) - - it('should propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=VARPA(B1:I1)', 2, 3, 4, '=NA()', false, 'a', '\'1', null], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-version.spec.ts b/test/unit/interpreter/function-version.spec.ts deleted file mode 100644 index 754eb4b575..0000000000 --- a/test/unit/interpreter/function-version.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ProtectedFunctionError} from '../../../src/errors' -import {InterpreterValue} from '../../../src/interpreter/InterpreterValue' -import {FunctionPlugin, FunctionPluginTypecheck} from '../../../src/interpreter/plugin/FunctionPlugin' -import {adr} from '../testUtils' - -describe('Function VERSION', () => { - describe('getting version', () => { - it('GPL license key', () => { - const engine = HyperFormula.buildFromArray([ - ['=VERSION()'], - ], { - licenseKey: 'gpl-v3', - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(`HyperFormula v${HyperFormula.version}, 1`) - }) - - it('missing license key', () => { - const engine = HyperFormula.buildFromArray([ - ['=VERSION()'], - ], { - licenseKey: '', - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(`HyperFormula v${HyperFormula.version}, 2`) - }) - - it('invalid license key', () => { - const engine = HyperFormula.buildFromArray([ - ['=VERSION()'], - ], { - licenseKey: '11111-11111-11111-11111-11111', - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(`HyperFormula v${HyperFormula.version}, 3`) - }) - - it('expired license key', () => { - const engine = HyperFormula.buildFromArray([ - ['=VERSION()'], - ], { - licenseKey: '80584-cc272-2e7c4-06f16-4db00', - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(`HyperFormula v${HyperFormula.version}, 4`) - }) - - it('correct license key', () => { - const engine = HyperFormula.buildFromArray([ - ['=VERSION()'], - ], { - licenseKey: 'internal-use-in-handsontable', - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(`HyperFormula v${HyperFormula.version}, table`) - }) - }) - - describe('registering', () => { - class VersionExtra extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'VERSION': { - method: 'version', - } - } - - public version(): InterpreterValue { - return 'version' - } - } - - it('should not allow registering VERSION formula', () => { - expect(() => { - HyperFormula.buildFromArray([ - ['=VERSION()'], - ], { - licenseKey: 'gpl-v3', - functionPlugins: [VersionExtra] - }) - }).toThrow(ProtectedFunctionError.cannotRegisterFunctionWithId('VERSION')) - }) - - it('should be available even if anyone unregistered', () => { - expect(() => { - HyperFormula.unregisterFunction('VERSION') - }).toThrow(ProtectedFunctionError.cannotUnregisterFunctionWithId('VERSION')) - - const engine = HyperFormula.buildFromArray([ - ['=VERSION()'], - ], { - licenseKey: 'gpl-v3', - }) - - expect(engine.getCellValue(adr('A1'))).toEqual(`HyperFormula v${HyperFormula.version}, 1`) - }) - }) -}) diff --git a/test/unit/interpreter/function-vlookup.spec.ts b/test/unit/interpreter/function-vlookup.spec.ts deleted file mode 100644 index 23b72e30ae..0000000000 --- a/test/unit/interpreter/function-vlookup.spec.ts +++ /dev/null @@ -1,826 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('ColumnIndex strategy', () => { - describe('VLOOKUP - args validation', () => { - it('not enough parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('too many parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, 2, TRUE(), "foo")'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('wrong type of first argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(D1:E1, A2:B3, 2, TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('wrong type of second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, "foo", 2, TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('wrong type of third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, "foo", TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong type of fourth argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, 2, "bar")'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should return error when index argument greater that range width', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, 3)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.IndexLarge)) - }) - - it('should return error when index is less than one', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, C2:D3, 0)'], - ['=VLOOKUP(1, C2:D3, -1)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('should return #VALUE error when the found value is a range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', '=A1:B1'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(2, A1:B5, 2)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should propagate errors properly', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1/0, B1:B1, 1)'], - ['=VLOOKUP(1, B1:B1, 1/0)'], - ['=VLOOKUP(1, A10:A11, 1, NA())'] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA)) - }) - }) - - describe('VLOOKUP', () => { - it('should find value in sorted range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(2, A1:B5, 2)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - }) - - it('should find value in sorted range using linearSearch', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - }) - - it('should return a single value even if there are more matching values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['2', 'c'], - ['2', 'd'], - ['2', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - expect(engine.getCellValue(adr('B6'))).toEqual(null) - expect(engine.getCellValue(adr('A7'))).toEqual(null) - }) - - it('should return the first matching value if RangeLookup = FALSE', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['2', 'c'], - ['2', 'd'], - ['2', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - }) - - it('should return the last matching value if RangeLookup = TRUE', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['2', 'c'], - ['2', 'd'], - ['2', 'e'], - ['=VLOOKUP(2, A1:B5, 2, TRUE())'] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('e') - }) - - it('works with wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 'a'], - [1, 'b'], - ['aaaa', 'c'], - ['ddaa', 'd'], - ['abcd', 'e'], - ['=VLOOKUP("*c*", A1:B5, 2, FALSE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('e') - }) - - it('on sorted data ignores wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 'a'], - [1, 'b'], - ['*c*', 'c'], - ['ddaa', 'd'], - ['abcd', 'e'], - ['=VLOOKUP("*c*", A1:B5, 2, TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('c') - }) - - it('should find value in unsorted range using linearSearch', () => { - const engine = HyperFormula.buildFromArray([ - ['5', 'a'], - ['4', 'b'], - ['3', 'c'], - ['2', 'd'], - ['1', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('d') - }) - - it('should find value in sorted range with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=TRUE()', 'd'], - ['foo', 'e'], - ['=VLOOKUP(TRUE(), A1:B5, 2, FALSE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('d') - }) - - it('should find value in unsorted range with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', 'a'], - ['4', 'b'], - ['foo', 'c'], - ['2', 'd'], - ['bar', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('d') - }) - - it('should return the lower bound for sorted values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['8', 'c'], - ['=VLOOKUP(4, A1:B3, 2, TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A4'))).toEqual('b') - }) - - it('should return the lower bound for sorted values if all are smaller than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=VLOOKUP(4, A1:B3, 2, TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A4'))).toEqual('c') - }) - - it('should return error when all values are greater', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=VLOOKUP(0, A1:B3, 2, TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should return error when value not present using linear search', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=VLOOKUP(4, A1:B3, 2, FALSE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should return #NA when searching in an empty range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(42, X10:Y20, 2)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should find value if index build during evaluation', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['=A1', 'b'], - ['2', 'c'], - ['=VLOOKUP(1, A1:B3, 2, TRUE())'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A4'))).toEqual('b') - }) - - it('should properly calculate absolute row index', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(3, A3:A5, 1, TRUE())'], - ['foo'], - ['1'], - ['2'], - ['3'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should work for standard matrices', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(3, A4:B6, 2, TRUE())'], - ['1', '2', '3'], - ['4', '5', '6'], - ['=TRANSPOSE(A2:C3)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - }) - - it('should work after updating standard matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(4, A4:B6, 2, TRUE())'], - ['1', '2', '3'], - ['4', '5', '6'], - ['=TRANSPOSE(A2:C3)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - - engine.setCellContents(adr('C2'), '5') - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - - it('should coerce empty arg to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['0', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(C3, A1:B5, 2)'], - ['=VLOOKUP(, A1:B5, 2)'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A6'))).toEqual('a') - expect(engine.getCellValue(adr('A7'))).toEqual('a') - }) - }) -}) - -describe('BinarySearchStrategy', () => { - describe('VLOOKUP - args validation', () => { - it('not enough parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('too many parameters', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, 2, TRUE(), "foo")'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('wrong type of first argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(D1:E1, A2:B3, 2, TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('wrong type of second argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, "foo", 2, TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('wrong type of third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, "foo", TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('wrong type of fourth argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, 2, "bar")'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should return error when index argument greater that range width', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, A2:B3, 3)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.IndexLarge)) - }) - - it('should return error when index is less than one', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1, C2:D3, 0)'], - ['=VLOOKUP(1, C2:D3, -1)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.LessThanOne)) - }) - - it('should propagate errors properly', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(1/0, B1:B1, 1)'], - ['=VLOOKUP(1, B1:B1, 1/0)'], - ['=VLOOKUP(1, A10:A11, 1, NA())'] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA)) - }) - }) - - describe('VLOOKUP', () => { - it('should find value in sorted range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(2, A1:B5, 2)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - }) - - it('should find value in sorted range using linearSearch', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - }) - - it('should return a single value even if there are more matching values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['2', 'c'], - ['2', 'd'], - ['2', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - expect(engine.getCellValue(adr('B6'))).toEqual(null) - expect(engine.getCellValue(adr('A7'))).toEqual(null) - }) - - it('should return the first matching value if RangeLookup = FALSE', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['2', 'c'], - ['2', 'd'], - ['2', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('b') - }) - - it('should return the last matching value if RangeLookup = TRUE', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['2', 'c'], - ['2', 'd'], - ['2', 'e'], - ['=VLOOKUP(2, A1:B5, 2, TRUE())'] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('e') - }) - - it('works with wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 'a'], - [1, 'b'], - ['aaaa', 'c'], - ['ddaa', 'd'], - ['abcd', 'e'], - ['=VLOOKUP("*c*", A1:B5, 2, FALSE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('e') - }) - - it('returns error when there is no matching value for the wildcard pattern', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 'a'], - [1, 'b'], - ['aaaa', 'c'], - ['ddaa', 'd'], - ['abbd', 'e'], - ['=VLOOKUP("*c*", A1:B5, 2, FALSE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('on sorted data ignores wildcards', () => { - const engine = HyperFormula.buildFromArray([ - ['abd', 'a'], - [1, 'b'], - ['*c*', 'c'], - ['ddaa', 'd'], - ['abcd', 'e'], - ['=VLOOKUP("*c*", A1:B5, 2, TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('c') - }) - - it('should find value in unsorted range using linearSearch', () => { - const engine = HyperFormula.buildFromArray([ - ['5', 'a'], - ['4', 'b'], - ['3', 'c'], - ['2', 'd'], - ['1', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('d') - }) - - it('should find value in sorted range with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=TRUE()', 'd'], - ['foo', 'e'], - ['=VLOOKUP(TRUE(), A1:B5, 2, FALSE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('d') - }) - - it('should find value in unsorted range with different types', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE()', 'a'], - ['4', 'b'], - ['foo', 'c'], - ['2', 'd'], - ['bar', 'e'], - ['=VLOOKUP(2, A1:B5, 2, FALSE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('d') - }) - - it('should return the lower bound for sorted values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['8', 'c'], - ['=VLOOKUP(4, A1:B3, 2, TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A4'))).toEqual('b') - }) - - it('should return the lower bound for sorted values if all are smaller than the search value', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=VLOOKUP(4, A1:B3, 2, TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A4'))).toEqual('c') - }) - - it('should return error when all values are greater', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=VLOOKUP(0, A1:B3, 2, TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should return #NA when searching in an empty range', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(42, X10:Y20, 2)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should return error when value not present using linear search', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['2', 'b'], - ['3', 'c'], - ['=VLOOKUP(4, A1:B3, 2, FALSE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should find value if index build during evaluation', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'a'], - ['=A1', 'b'], - ['2', 'c'], - ['=VLOOKUP(1, A1:B3, 2, TRUE())'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A4'))).toEqual('b') - }) - - it('should properly calculate absolute row index', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(3, A3:A5, 1, TRUE())'], - ['foo'], - ['1'], - ['2'], - ['3'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should work for standard matrices', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(3, A4:B6, 2, TRUE())'], - ['1', '2', '3'], - ['4', '5', '6'], - ['=TRANSPOSE(A2:C3)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - }) - - it('should work after updating standard matrix', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(4, A4:B6, 2, TRUE())'], - ['1', '2', '3'], - ['4', '5', '6'], - ['=TRANSPOSE(A2:C3)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - - engine.setCellContents(adr('C2'), '5') - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - - it('should coerce empty arg to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['0', 'a'], - ['2', 'b'], - ['3', 'c'], - ['4', 'd'], - ['5', 'e'], - ['=VLOOKUP(C3, A1:B5, 2)'], - ['=VLOOKUP(, A1:B5, 2)'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A6'))).toEqual('a') - expect(engine.getCellValue(adr('A7'))).toEqual('a') - }) - }) - - it('should calculate indexes properly when using binary search', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(4, A5:A10, 1, TRUE())'], - [], - [], - [], - ['1'], - ['2'], - ['3'], - ['4'], - ['5'], - ], {useColumnIndex: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('should calculate indexes properly when using naive approach', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(4, A5:A10, 1, FALSE())'], - [], - [], - [], - ['1'], - ['2'], - ['3'], - ['4'], - ['5'], - ], {useColumnIndex: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('should coerce null to zero when using naive approach', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(, A2:A4, 1, FALSE())'], - [1], - [3], - [0], - ], {useColumnIndex: false}) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - }) - - it('should work on column ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP(2,B:C,2)', 1, 'a'], - [null, 2, 'b'], - [null, 3, 'c'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual('b') - }) - - it('works for strings, is not case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['a', '1'], - ['b', '2'], - ['c', '3'], - ['A', '4'], - ['B', '5'], - ['=VLOOKUP("A", A1:B5, 2, FALSE())'] - ], {caseSensitive: false}) - - expect(engine.getCellValue(adr('A6'))).toEqual(1) - }) - - it('works for strings, is not case sensitive even if config defines case sensitivity', () => { - const engine = HyperFormula.buildFromArray([ - ['a', '1'], - ['b', '2'], - ['c', '3'], - ['A', '4'], - ['B', '5'], - ['=VLOOKUP("A", A1:B5, 2, FALSE())'] - ], {useColumnIndex: false, caseSensitive: true}) - - expect(engine.getCellValue(adr('A6'))).toEqual(1) - }) - - it('should find value in sorted range', () => { - const engine = HyperFormula.buildFromArray([ - ['a', '1'], - ['B', '2'], - ['c', '3'], - ['d', '4'], - ['e', '5'], - ['=VLOOKUP("b", A1:B5, 2)'], - ], {useColumnIndex: false, caseSensitive: false}) - expect(engine.getCellValue(adr('A6'))).toEqual(2) - }) - - it('should properly report no match', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP("0", A2:A5, 1)'], - [1], - [2], - [3], - ['\'1'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should properly report approximate matching', () => { - const engine = HyperFormula.buildFromArray([ - ['=VLOOKUP("2", A2:A5, 1)'], - [1], - [2], - [3], - ['\'1'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('1') - }) - - it('works with a column range reference to an empty sheet', () => { - const hf = HyperFormula.buildFromSheets({ - table1: [], - table2: [['=VLOOKUP("42", table1!A:C, 1)']], - }) - - expect(hf.getCellValue(adr('A1', 1))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-weekday.spec.ts b/test/unit/interpreter/function-weekday.spec.ts deleted file mode 100644 index 8ad7b5a555..0000000000 --- a/test/unit/interpreter/function-weekday.spec.ts +++ /dev/null @@ -1,131 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function WEEKDAY', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY(1, 2, 3)'], - ['=WEEKDAY()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY("foo", 1)'], - ['=WEEKDAY(2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for wrong value of args', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY(-1, 1)'], - ['=WEEKDAY(2, 9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.BadMode)) - }) - - it('should work for strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY("31/07/2020")'], - ['=WEEKDAY("31/07/2020", "1")'], - ['=WEEKDAY("31/07/2020", "2")'], - ['=WEEKDAY("31/07/2020", "3")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(6) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('should work for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY(0)'], - ['=WEEKDAY(0, 1)'], - ['=WEEKDAY(0, 2)'], - ['=WEEKDAY(0, 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(7) - expect(engine.getCellValue(adr('A2'))).toEqual(7) - expect(engine.getCellValue(adr('A3'))).toEqual(6) - expect(engine.getCellValue(adr('A4'))).toEqual(5) - }) - - it('should work for strings with different nullDate', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY("31/07/2020")'], - ['=WEEKDAY("31/07/2020", "1")'], - ['=WEEKDAY("31/07/2020", "2")'], - ['=WEEKDAY("31/07/2020", "3")'], - ], {nullDate: {day: 20, month: 10, year: 1920}}) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(6) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('should work for strings with compatibility mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY("31/07/2020")'], - ['=WEEKDAY("31/07/2020", "1")'], - ['=WEEKDAY("31/07/2020", "2")'], - ['=WEEKDAY("31/07/2020", "3")'], - ], {leapYear1900: true}) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(6) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('should work for strings with compatibility mode and different nullDate', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKDAY("31/07/2020")'], - ['=WEEKDAY("31/07/2020", "1")'], - ['=WEEKDAY("31/07/2020", "2")'], - ['=WEEKDAY("31/07/2020", "3")'], - ], {leapYear1900: true, nullDate: {day: 20, month: 10, year: 1920}}) - - expect(engine.getCellValue(adr('A1'))).toEqual(6) - expect(engine.getCellValue(adr('A2'))).toEqual(6) - expect(engine.getCellValue(adr('A3'))).toEqual(5) - expect(engine.getCellValue(adr('A4'))).toEqual(4) - }) - - it('big test', () => { - const args = [1, 2, 3, 11, 12, 13, 14, 15, 16, 17] - const dates = ['13/08/2020', '14/08/2020', '15/08/2020', '16/08/2020', '17/08/2020', '18/08/2020', '19/08/2020'] - const arrs = [] - for (const arg of args) { - const arr = [] - for (const date of dates) { - arr.push(`=WEEKDAY("${date}", ${arg})`) - } - arrs.push(arr) - } - const engine = HyperFormula.buildFromArray(arrs) - expect(engine.getSheetValues(0)).toEqual( - [[5, 6, 7, 1, 2, 3, 4], - [4, 5, 6, 7, 1, 2, 3], - [3, 4, 5, 6, 0, 1, 2], - [4, 5, 6, 7, 1, 2, 3], - [3, 4, 5, 6, 7, 1, 2], - [2, 3, 4, 5, 6, 7, 1], - [1, 2, 3, 4, 5, 6, 7], - [7, 1, 2, 3, 4, 5, 6], - [6, 7, 1, 2, 3, 4, 5], - [5, 6, 7, 1, 2, 3, 4]]) - }) -}) diff --git a/test/unit/interpreter/function-weeknum.spec.ts b/test/unit/interpreter/function-weeknum.spec.ts deleted file mode 100644 index 90016abc97..0000000000 --- a/test/unit/interpreter/function-weeknum.spec.ts +++ /dev/null @@ -1,145 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function WEEKNUM', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM(1, 2, 3)'], - ['=WEEKNUM()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM("foo", 1)'], - ['=WEEKNUM(2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should not work for wrong value of args', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM(-1, 1)'], - ['=WEEKNUM(2, 9)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.BadMode)) - }) - - it('should work for strings', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM("02/08/2020")'], - ['=WEEKNUM("02/08/2020", "1")'], - ['=WEEKNUM("02/08/2020", "2")'], - ['=WEEKNUM("02/08/2020", "21")'], - ['=WEEKNUM("02/08/2017", "2")'], - ['=WEEKNUM("02/08/2017", "21")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(32) - expect(engine.getCellValue(adr('A2'))).toEqual(32) - expect(engine.getCellValue(adr('A3'))).toEqual(31) - expect(engine.getCellValue(adr('A4'))).toEqual(31) - expect(engine.getCellValue(adr('A5'))).toEqual(32) - expect(engine.getCellValue(adr('A6'))).toEqual(31) - }) - - it('should work for numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM(0)'], - ['=WEEKNUM(0, 1)'], - ['=WEEKNUM(0, 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(52) - expect(engine.getCellValue(adr('A2'))).toEqual(52) - expect(engine.getCellValue(adr('A3'))).toEqual(53) - }) - - it('should work for strings with different nullDate', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM("02/08/2020")'], - ['=WEEKNUM("02/08/2020", "1")'], - ['=WEEKNUM("02/08/2020", "2")'], - ['=WEEKNUM("02/08/2020", "21")'], - ['=WEEKNUM("02/08/2017", "2")'], - ['=WEEKNUM("02/08/2017", "21")'], - ], {nullDate: {day: 20, month: 10, year: 1920}}) - - expect(engine.getCellValue(adr('A1'))).toEqual(32) - expect(engine.getCellValue(adr('A2'))).toEqual(32) - expect(engine.getCellValue(adr('A3'))).toEqual(31) - expect(engine.getCellValue(adr('A4'))).toEqual(31) - expect(engine.getCellValue(adr('A5'))).toEqual(32) - expect(engine.getCellValue(adr('A6'))).toEqual(31) - }) - - it('should work for strings with compatibility mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM("02/08/2020")'], - ['=WEEKNUM("02/08/2020", "1")'], - ['=WEEKNUM("02/08/2020", "2")'], - ['=WEEKNUM("02/08/2020", "21")'], - ['=WEEKNUM("02/08/2017", "2")'], - ['=WEEKNUM("02/08/2017", "21")'], - ], {leapYear1900: true}) - - expect(engine.getCellValue(adr('A1'))).toEqual(32) - expect(engine.getCellValue(adr('A2'))).toEqual(32) - expect(engine.getCellValue(adr('A3'))).toEqual(31) - expect(engine.getCellValue(adr('A4'))).toEqual(31) - expect(engine.getCellValue(adr('A5'))).toEqual(32) - expect(engine.getCellValue(adr('A6'))).toEqual(31) - }) - it('should work for strings with compatibility mode and different nullDate', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEEKNUM("02/08/2020")'], - ['=WEEKNUM("02/08/2020", "1")'], - ['=WEEKNUM("02/08/2020", "2")'], - ['=WEEKNUM("02/08/2020", "21")'], - ['=WEEKNUM("02/08/2017", "2")'], - ['=WEEKNUM("02/08/2017", "21")'], - ], {leapYear1900: true, nullDate: {day: 20, month: 10, year: 1920}}) - - expect(engine.getCellValue(adr('A1'))).toEqual(32) - expect(engine.getCellValue(adr('A2'))).toEqual(32) - expect(engine.getCellValue(adr('A3'))).toEqual(31) - expect(engine.getCellValue(adr('A4'))).toEqual(31) - expect(engine.getCellValue(adr('A5'))).toEqual(32) - expect(engine.getCellValue(adr('A6'))).toEqual(31) - }) - - it('big test', () => { - const args = [1, 2, 11, 12, 13, 14, 15, 16, 17, 21] - const dates = ['13/08/2020', '14/08/2020', '15/08/2020', '16/08/2020', '17/08/2020', '18/08/2020', '19/08/2020'] - const arrs = [] - for (const arg of args) { - const arr = [] - for (const date of dates) { - arr.push(`=WEEKNUM("${date}", ${arg})`) - } - arrs.push(arr) - } - const engine = HyperFormula.buildFromArray(arrs) - expect(engine.getSheetValues(0)).toEqual( - [[33, 33, 33, 34, 34, 34, 34], - [33, 33, 33, 33, 34, 34, 34], - [33, 33, 33, 33, 34, 34, 34], - [33, 33, 33, 33, 33, 34, 34], - [33, 33, 33, 33, 33, 33, 34], - [34, 34, 34, 34, 34, 34, 34], - [33, 34, 34, 34, 34, 34, 34], - [33, 33, 34, 34, 34, 34, 34], - [33, 33, 33, 34, 34, 34, 34], - [33, 33, 33, 33, 34, 34, 34], - ]) - }) -}) diff --git a/test/unit/interpreter/function-weibull.dist.spec.ts b/test/unit/interpreter/function-weibull.dist.spec.ts deleted file mode 100644 index a11905d89e..0000000000 --- a/test/unit/interpreter/function-weibull.dist.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function WEIBULL.DIST', () => { - it('should return error for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEIBULL.DIST(1, 2, 3)'], - ['=WEIBULL.DIST(1, 2, 3, 4, 5)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should return error for arguments of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEIBULL.DIST("foo", 2, 3, TRUE())'], - ['=WEIBULL.DIST(1, "baz", 3, TRUE())'], - ['=WEIBULL.DIST(1, 2, "baz", TRUE())'], - ['=WEIBULL.DIST(1, 2, 3, "abcd")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('should work as cdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEIBULL.DIST(0.1, 1, 2, TRUE())'], - ['=WEIBULL.DIST(0.5, 2, 4, TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.048770575499286, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0155035629945915, 6) - }) - - it('should work as pdf', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEIBULL.DIST(0.1, 1, 2, FALSE())'], - ['=WEIBULL.DIST(0.5, 2, 4, FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.475614712250357, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.061531027312838, 6) - }) - - it('checks bounds', () => { - const engine = HyperFormula.buildFromArray([ - ['=WEIBULL.DIST(0, 1, 1, FALSE())'], - ['=WEIBULL.DIST(-0.01, 0.01, 0.01, FALSE())'], - ['=WEIBULL.DIST(0, 0, 0.01, FALSE())'], - ['=WEIBULL.DIST(0, 0.01, 0, FALSE())'], - ]) - - //product #2 returns different value - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-workday.intl.spec.ts b/test/unit/interpreter/function-workday.intl.spec.ts deleted file mode 100644 index d41ce23395..0000000000 --- a/test/unit/interpreter/function-workday.intl.spec.ts +++ /dev/null @@ -1,140 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function WORKDAY.INTL', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WORKDAY.INTL(1)', '=WORKDAY.INTL(1, 1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should check for types or value of third argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=WORKDAY.INTL(0, 1, TRUE())'], - ['=WORKDAY.INTL(0, 1, "1")'], - ['=WORKDAY.INTL(0, 1, "1010102")'], - ['=WORKDAY.INTL(0, 1, -1)'], - ['=WORKDAY.INTL(0, 1, "1111111")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WeekendString)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WeekendString)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.WeekendString)) - }) - - it('works correctly for first two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WORKDAY.INTL(1000, 1)'], - ['=WORKDAY.INTL(1000.9, 1.9)'], - ['=WORKDAY.INTL(1000.9, -1)'], - ['=WORKDAY.INTL(1000, -1.9)'], - ['=WORKDAY.INTL(1000, 0)'], - ['=WORKDAY.INTL(1000, 0.9)'], - ['=WORKDAY.INTL(1000, -0.9)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1003) - expect(engine.getCellValue(adr('A2'))).toEqual(1003) - expect(engine.getCellValue(adr('A3'))).toEqual(999) - expect(engine.getCellValue(adr('A4'))).toEqual(999) - expect(engine.getCellValue(adr('A5'))).toEqual(1000) - expect(engine.getCellValue(adr('A6'))).toEqual(1000) - expect(engine.getCellValue(adr('A7'))).toEqual(1000) - }) - - it('today plus 1', () => { - const engine = HyperFormula.buildFromArray([ - ['=WORKDAY.INTL("29/09/2020", 1)'], - ['=WORKDAY.INTL("29/09/2020", 1, 3)'], - ['=WORKDAY.INTL("29/09/2020", 1, 4)'], - ['=WORKDAY.INTL("29/09/2020", 1, 5)'], - ['=WORKDAY.INTL("29/09/2020", 1, 6)'], - ['=WORKDAY.INTL("29/09/2020", 1, 13)'], - ['=WORKDAY.INTL("29/09/2020", 1, 14)'], - ['=WORKDAY.INTL("29/09/2020", 1, 15)'], - ['=WORKDAY.INTL("29/09/2020", 1, "1011111")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(44104) - expect(engine.getCellValue(adr('A2'))).toEqual(44104) - expect(engine.getCellValue(adr('A3'))).toEqual(44105) - expect(engine.getCellValue(adr('A4'))).toEqual(44106) - expect(engine.getCellValue(adr('A5'))).toEqual(44104) - expect(engine.getCellValue(adr('A6'))).toEqual(44104) - expect(engine.getCellValue(adr('A7'))).toEqual(44105) - expect(engine.getCellValue(adr('A8'))).toEqual(44104) - expect(engine.getCellValue(adr('A9'))).toEqual(44110) - }) - - it('today minus 1', () => { - const engine = HyperFormula.buildFromArray([ - ['=WORKDAY.INTL("29/09/2020", -1)'], - ['=WORKDAY.INTL("29/09/2020", -1, 2)'], - ['=WORKDAY.INTL("29/09/2020", -1, 3)'], - ['=WORKDAY.INTL("29/09/2020", -1, 4)'], - ['=WORKDAY.INTL("29/09/2020", -1, 5)'], - ['=WORKDAY.INTL("29/09/2020", -1, 12)'], - ['=WORKDAY.INTL("29/09/2020", -1, 13)'], - ['=WORKDAY.INTL("29/09/2020", -1, 14)'], - ['=WORKDAY.INTL("29/09/2020", -1, "1011111")'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(44102) - expect(engine.getCellValue(adr('A2'))).toEqual(44100) - expect(engine.getCellValue(adr('A3'))).toEqual(44101) - expect(engine.getCellValue(adr('A4'))).toEqual(44102) - expect(engine.getCellValue(adr('A5'))).toEqual(44102) - expect(engine.getCellValue(adr('A6'))).toEqual(44101) - expect(engine.getCellValue(adr('A7'))).toEqual(44102) - expect(engine.getCellValue(adr('A8'))).toEqual(44102) - expect(engine.getCellValue(adr('A9'))).toEqual(44096) - }) - - it('this year', () => { - const engine = HyperFormula.buildFromArray([ - ['29/09/2020', '=A1+0.1', '31/12/2019', '01/01/2021', '27/09/2020'], - ['=WORKDAY.INTL("01/01/2020", 262, 1)'], - ['=WORKDAY.INTL("01/01/2020", 262, 1, A1:A1)'], - ['=WORKDAY.INTL("01/01/2020", 262, 1, A1:B1)'], - ['=WORKDAY.INTL("01/01/2020", 262, 1, A1:D1)'], - ['=WORKDAY.INTL("01/01/2020", 262, 1, A1:E1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(44197) - expect(engine.getCellValue(adr('A3'))).toEqual(44200) - expect(engine.getCellValue(adr('A4'))).toEqual(44200) - expect(engine.getCellValue(adr('A5'))).toEqual(44201) - expect(engine.getCellValue(adr('A6'))).toEqual(44201) - }) - - it('should output correct values', () => { - const engine = HyperFormula.buildFromArray([ - ['01/01/2020', '=A1+5', '=A1+8', '=A1+9', '=A1+15', '=A1+18', '=A1+19', '=A1+32', '=A1+54', '=A1+55'], - ['=WORKDAY.INTL(A1, 91, "0000000", A1:J1)'], - ['=WORKDAY.INTL(A1+7, 9, "0000000", A1:J1)'], - ['=WORKDAY.INTL(A1+7, 86, "0000000", A1:J1)'], - ['=WORKDAY.INTL(A1+13, 34, "0000000", A1:J1)'], - ['=WORKDAY.INTL(A1+50, 5, "0000000", A1:J1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(43931) - expect(engine.getCellValue(adr('A3'))).toEqual(43852) - expect(engine.getCellValue(adr('A4'))).toEqual(43932) - expect(engine.getCellValue(adr('A5'))).toEqual(43882) - expect(engine.getCellValue(adr('A6'))).toEqual(43888) - }) - - it('checks types in last argument', () => { - const engine = HyperFormula.buildFromArray([ - [true, '\'1', null, '=NA()'], - ['=WORKDAY.INTL(1000, 1, 1, A1:A1)'], - ['=WORKDAY.INTL(1000, 1, 1, B1:B1)'], - ['=WORKDAY.INTL(1000, 1, 1, C1:C1)'], - ['=WORKDAY.INTL(1000, 1, 1, A1:D1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A4'))).toEqual(1003) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-workday.spec.ts b/test/unit/interpreter/function-workday.spec.ts deleted file mode 100644 index b7e556bccb..0000000000 --- a/test/unit/interpreter/function-workday.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function WORKDAY', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WORKDAY(1)', '=WORKDAY(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works correctly for first two arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=WORKDAY(1000, 1)'], - ['=WORKDAY(1000.9, 1.9)'], - ['=WORKDAY(1000.9, -1)'], - ['=WORKDAY(1000, -1.9)'], - ['=WORKDAY(1000, 0)'], - ['=WORKDAY(1000, 0.9)'], - ['=WORKDAY(1000, -0.9)'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1003) - expect(engine.getCellValue(adr('A2'))).toEqual(1003) - expect(engine.getCellValue(adr('A3'))).toEqual(999) - expect(engine.getCellValue(adr('A4'))).toEqual(999) - expect(engine.getCellValue(adr('A5'))).toEqual(1000) - expect(engine.getCellValue(adr('A6'))).toEqual(1000) - expect(engine.getCellValue(adr('A7'))).toEqual(1000) - }) - - it('this year', () => { - const engine = HyperFormula.buildFromArray([ - ['29/09/2020', '=A1+0.1', '31/12/2019', '01/01/2021', '27/09/2020'], - ['=WORKDAY("01/01/2020", 262)'], - ['=WORKDAY("01/01/2020", 262, A1:A1)'], - ['=WORKDAY("01/01/2020", 262, A1:B1)'], - ['=WORKDAY("01/01/2020", 262, A1:D1)'], - ['=WORKDAY("01/01/2020", 262, A1:E1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(44197) - expect(engine.getCellValue(adr('A3'))).toEqual(44200) - expect(engine.getCellValue(adr('A4'))).toEqual(44200) - expect(engine.getCellValue(adr('A5'))).toEqual(44201) - expect(engine.getCellValue(adr('A6'))).toEqual(44201) - }) - - it('should output correct values', () => { - const engine = HyperFormula.buildFromArray([ - ['01/01/2020', '=A1+5', '=A1+8', '=A1+9', '=A1+15', '=A1+18', '=A1+19', '=A1+32', '=A1+54', '=A1+55'], - ['=WORKDAY(A1, 65, A1:J1)'], - ['=WORKDAY(A1+7, 6, A1:J1)'], - ['=WORKDAY(A1+7, 62, A1:J1)'], - ['=WORKDAY(A1+13, 26, A1:J1)'], - ['=WORKDAY(A1+50, 3, A1:J1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(43931) - expect(engine.getCellValue(adr('A3'))).toEqual(43852) - expect(engine.getCellValue(adr('A4'))).toEqual(43934) - expect(engine.getCellValue(adr('A5'))).toEqual(43882) - expect(engine.getCellValue(adr('A6'))).toEqual(43888) - }) - - it('checks types in last argument', () => { - const engine = HyperFormula.buildFromArray([ - [true, '\'1', null, '=NA()'], - ['=WORKDAY(1000, 1, A1:A1)'], - ['=WORKDAY(1000, 1, B1:B1)'], - ['=WORKDAY(1000, 1, C1:C1)'], - ['=WORKDAY(1000, 1, A1:D1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - expect(engine.getCellValue(adr('A4'))).toEqual(1003) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/function-xlookup.spec.ts b/test/unit/interpreter/function-xlookup.spec.ts deleted file mode 100644 index fc3f4fe1bf..0000000000 --- a/test/unit/interpreter/function-xlookup.spec.ts +++ /dev/null @@ -1,1276 +0,0 @@ -import { HyperFormula, ErrorType } from '../../../src' -import { ErrorMessage } from '../../../src/error-message' -import { adr, detailedError } from '../testUtils' -import { AbsoluteCellRange } from '../../../src/AbsoluteCellRange' - -describe('Function XLOOKUP', () => { - describe('validates arguments', () => { - it('returns error when less than 3 arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:B3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('returns error when more than 5 arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:A3, B2:B3, "foo", 0, 1, 42)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('returns error when shapes of lookupArray and returnArray are incompatible', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, B1:B10, C1:C9)'], // returnArray too short - ['=XLOOKUP(1, B1:B10, C1:C11)'], // returnArray too long - ['=XLOOKUP(1, B1:B10, C1:D5)'], // returnArray too short - ['=XLOOKUP(1, B1:E1, B2:D2)'], // returnArray too short - ['=XLOOKUP(1, B1:E1, B2:F2)'], // returnArray too long - ['=XLOOKUP(1, B1:E1, B2:C3)'], // returnArray too short - ['=XLOOKUP(1, B1:B3, C1:E1)'], // transposed - ['=XLOOKUP(1, C1:E1, B1:B3)'], // transposed - ['=XLOOKUP(1, B1:C2, D3:E4)'], // lookupArray: 2d range - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A8'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - expect(engine.getCellValue(adr('A9'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongDimension)) - }) - - it('returns error when matchMode is of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, B1:B2, C1:C2, 0, -2)'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 3)'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 0.5)'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, "string")'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, B1:B2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('returns error when searchMode is of wrong type', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 0, -3)'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 0, 3)'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 0, 0)'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 0, 0.5)'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 0, "string")'], - ['=XLOOKUP(1, B1:B2, C1:C2, 0, 0, D1:D2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.BadMode)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A6'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('propagates errors properly', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1/0, B1:B1, 1)'], - ['=XLOOKUP(1, B1:B1, 1/0)'], - ['=XLOOKUP(1, A10:A11, NA())'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.NA)) - }) - }) - - describe('with default matchMode and searchMode', () => { - it('finds value in a sorted row', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, B1:D1, B1:D1)', 1, 2, 3], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('finds value in an unsorted row', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, B1:D1, B1:D1)', 4, 2, 3], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('finds value in a sorted column', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, B1:B3, B1:B3)', 1], - ['', 2], - ['', 3], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('finds value in an unsorted column', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, B1:B3, B1:B3)', 4], - ['', 2], - ['', 3], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('when key is not found, returns ifNotFound value or NA error', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, B1:B3, B1:B3)'], - ['=XLOOKUP(2, B1:D1, B1:D1)'], - ['=XLOOKUP(2, B1:B3, B1:B3, "not found")'], - ['=XLOOKUP(2, B1:D1, B1:D1, "not found")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - expect(engine.getCellValue(adr('A3'))).toEqual('not found') - expect(engine.getCellValue(adr('A4'))).toEqual('not found') - }) - - it('works when returnArray is shifted (vertical search)', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, B1:B3, C11:C13)', 1], - ['', 2], - ['', 3], - [], - [], - [], - [], - [], - [], - [], - ['', '', 'a'], - ['', '', 'b'], - ['', '', 'c'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('b') - }) - - it('works when returnArray is shifted (horizontal search)', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, B1:D1, C2:E2)', '1', '2', '3'], - ['', '', 'a', 'b', 'c'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('b') - }) - - it('should not perform the wildcard match unless matchMode=2', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - it('should not perform the wildcard match unless matchMode=2 (ColumnIndex)', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.ValueNotFound)) - }) - - describe('when lookupArray is a single-cell range', () => { - it('returns single cell, when returnArray is also a single-cell range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, B1:B1, C1:C1)', 1, 'a'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('a') - }) - - it('returns a vertical range, when returnArray is a vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, B1:B1, A3:A4)', 1], - [], - ['b'], - ['c'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('b') - expect(engine.getCellValue(adr('A2'))).toEqual('c') - }) - - it('returns a horizontal range, when returnArray is a horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - [1, 'b', 'c'], - ['=XLOOKUP(1, A1:A1, B1:C1)'], - ]) - - expect(engine.getCellValue(adr('A2'))).toEqual('b') - expect(engine.getCellValue(adr('B2'))).toEqual('c') - }) - }) - - it('finds an empty cell', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("", B1:D1, B2:D2)', 1, 2, ''], - ['', 'a', 'b', 'c'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('c') - }) - }) - - describe('with BinarySearch column search strategy, when provided with searchMode =', () => { - it('1, finds the first match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:E2, A3:E3, "NotFound", 0, 1)'], - [2, 1, 3, 1, 4], - [1, 2, 3, 4, 5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('1, finds the first match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:A6, B2:B6, "NotFound", 0, 1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('1, returns "NotFound" if there is no match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(5, A2:A6, B2:B6, "NotFound", 0, 1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('-1, finds the last match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:E2, A3:E3, "NotFound", 0, -1)'], - [2, 1, 3, 1, 4], - [1, 2, 3, 4, 5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('-1, finds the last match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:A6, B2:B6, "NotFound", 0, -1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('-1, returns "NotFound" if there is no match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(5, A2:A6, B2:B6, "NotFound", 0, -1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('2, finds the value in horizontal range sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:E2, A2:E2, "NotFound", 0, 2)'], - [1, 2, 2, 5, 5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('2, finds the value in vertical range sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:A6, A2:A6, "NotFound", 0, 2)'], - [1], - [2], - [2], - [5], - [5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('2, returns "NotFound" if there is no match in a range sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, A2:A6, "NotFound", 0, 2)'], - [1], - [2], - [2], - [5], - [5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('-2, finds the value in horizontal range sorted descending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:E2, A2:E2, "NotFound", 0, -2)'], - [5, 2, 2, 1, 1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('-2, finds the value in vertical range sorted descending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:A6, A2:A6, "NotFound", 0, -2)'], - [5], - [2], - [2], - [1], - [1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('-2, returns "NotFound" if there is no match in a range sorted descending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, A2:A6, "NotFound", 0, -2)'], - [5], - [2], - [2], - [1], - [1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - }) - - describe('with ColumnIndex column search strategy, when provided with searchMode =', () => { - it('1, finds the first match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:E2, A3:E3, "NotFound", 0, 1)'], - [2, 1, 3, 1, 4], - [1, 2, 3, 4, 5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('1, finds the first match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:A6, B2:B6, "NotFound", 0, 1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('1, returns "NotFound" if there is no match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(5, A2:A6, B2:B6, "NotFound", 0, 1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('-1, finds the last match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:E2, A3:E3, "NotFound", 0, -1)'], - [2, 1, 3, 1, 4], - [1, 2, 3, 4, 5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('-1, finds the last match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(1, A2:A6, B2:B6, "NotFound", 0, -1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(4) - }) - - it('-1, returns "NotFound" if there is no match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(5, A2:A6, B2:B6, "NotFound", 0, -1)'], - [2, 1], - [1, 2], - [3, 3], - [1, 4], - [4, 5] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('2, finds the value in horizontal range sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:E2, A2:E2, "NotFound", 0, 2)'], - [1, 2, 2, 5, 5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('2, finds the value in vertical range sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:A6, A2:A6, "NotFound", 0, 2)'], - [1], - [2], - [2], - [5], - [5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('2, returns "NotFound" if there is no match in a range sorted ascending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, A2:A6, "NotFound", 0, 2)'], - [1], - [2], - [2], - [5], - [5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('-2, finds the value in horizontal range sorted descending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:E2, A2:E2, "NotFound", 0, -2)'], - [5, 2, 2, 1, 1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('-2, finds the value in vertical range sorted descending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(2, A2:A6, A2:A6, "NotFound", 0, -2)'], - [5], - [2], - [2], - [1], - [1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) - - it('-2, returns "NotFound" if there is no match in a range sorted descending', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, A2:A6, "NotFound", 0, -2)'], - [5], - [2], - [2], - [1], - [1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - }) - - describe('with BinarySearch column search strategy, when provided with matchMode =', () => { - describe('-1 (looking for a lower bound)', () => { - describe('in array ordered ascending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [1, 2, 42, 50, 51], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns a lower bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [1, 2, 40, 50, 51], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(40) - }) - - it('returns a lower bound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [1, 2, 3, 4, 5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - - it('returns NotFound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [43, 44, 45, 46, 47], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - }) - - describe('in array ordered descending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [55, 54, 42, 2, 1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns a lower bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [55, 54, 40, 2, 1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(40) - }) - - it('returns a lower bound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [5, 4, 3, 2, 1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - - it('returns NotFound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [100, 90, 80, 70, 60], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - }) - - it('returns a lower bound if there is no match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:E2, A3:E3, "NotFound", -1, 1)'], - [2, 1, 4, 2, 5], - [1, 2, 3, 4, 5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('returns a lower bound if there is no match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, B2:B6, "NotFound", -1, 1)'], - [2, 1], - [1, 2], - [4, 3], - [2, 4], - [5, 5] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - }) - - describe('1 (looking for a upper bound', () => { - describe('in array ordered ascending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [1, 2, 42, 50, 51], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns an upper bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [1, 2, 44, 50, 51], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(44) - }) - - it('returns NotFound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [1, 2, 3, 4, 5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('returns an upper bound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [43, 44, 45, 46, 47], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(43) - }) - }) - - describe('in array ordered descending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [55, 54, 42, 2, 1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns an upper bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [55, 54, 44, 2, 1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(44) - }) - - it('returns NotFound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [5, 4, 3, 2, 1], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('returns an upper bound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [100, 90, 80, 70, 60], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(60) - }) - }) - - it('returns an upper bound if there is no match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:E2, A3:E3, "NotFound", 1, 1)'], - [2, 1, 4, 2, 5], - [1, 2, 3, 4, 5], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('returns an upper bound if there is no match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, B2:B6, "NotFound", 1, 1)'], - [2, 1], - [1, 2], - [4, 3], - [2, 4], - [5, 5] - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - }) - - describe('2 (wildcard match)', () => { - describe('for a horizontal range', () => { - it('when searchMode = 1, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, 1)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = 2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, 2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, -2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -1, returns the last matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, -1)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a2b222') - }) - - it('when there are no matching items, returns NotFound (all searchModes)', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, 1)'], - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, -1)'], - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, 2)'], - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, -2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A2'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A3'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A4'))).toEqual('NotFound') - }) - }) - - describe('for a vertical range', () => { - it('when searchMode = 1, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, 1)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = 2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, 2)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, -2)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -1, returns the last matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, -1)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a2b222') - }) - - it('when there are no matching items, returns NotFound (all searchModes)', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, 1)'], - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, -1)'], - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, 2)'], - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, -2)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: false }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A2'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A3'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A4'))).toEqual('NotFound') - }) - }) - }) - }) - - describe('with ColumnIndex column search strategy, when provided with matchMode =', () => { - describe('-1 (looking for a lower bound', () => { - describe('in array ordered ascending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [1, 2, 42, 50, 51], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns a lower bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [1, 2, 40, 50, 51], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(40) - }) - - it('returns a lower bound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [1, 2, 3, 4, 5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - - it('returns NotFound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, 2)'], - [43, 44, 45, 46, 47], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - }) - - describe('in array ordered descending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [55, 54, 42, 2, 1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns a lower bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [55, 54, 40, 2, 1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(40) - }) - - it('returns a lower bound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [5, 4, 3, 2, 1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(5) - }) - - it('returns NotFound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", -1, -2)'], - [100, 90, 80, 70, 60], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - }) - - it('returns a lower bound if there is no match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:E2, A3:E3, "NotFound", -1, 1)'], - [2, 1, 4, 2, 5], - [1, 2, 3, 4, 5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - - it('returns a lower bound if there is no match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, B2:B6, "NotFound", -1, 1)'], - [2, 1], - [1, 2], - [4, 3], - [2, 4], - [5, 5] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - }) - - describe('1 (looking for a upper bound', () => { - describe('in array ordered ascending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [1, 2, 42, 50, 51], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns an upper bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [1, 2, 44, 50, 51], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(44) - }) - - it('returns NotFound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [1, 2, 3, 4, 5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('returns an upper bound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, 2)'], - [43, 44, 45, 46, 47], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(43) - }) - }) - - describe('in array ordered descending', () => { - it('returns exact match if exists', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [55, 54, 42, 2, 1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('returns an upper bound when there is no exact match', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [55, 54, 44, 2, 1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(44) - }) - - it('returns NotFound when all elements are smaller than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [5, 4, 3, 2, 1], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - }) - - it('returns an upper bound when all elements are greater than the key', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(42, A2:E2, A2:E2, "NotFound", 1, -2)'], - [100, 90, 80, 70, 60], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(60) - }) - }) - - it('returns an upper bound if there is no match in unsorted horizontal range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:E2, A3:E3, "NotFound", 1, 1)'], - [2, 1, 4, 2, 5], - [1, 2, 3, 4, 5], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('returns an upper bound if there is no match in unsorted vertical range', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP(3, A2:A6, B2:B6, "NotFound", 1, 1)'], - [2, 1], - [1, 2], - [4, 3], - [2, 4], - [5, 5] - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - }) - - describe('2 (wildcard match)', () => { - describe('for a horizontal range', () => { - it('when searchMode = 1, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, 1)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = 2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, 2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, -2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -1, returns the last matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:E2, A2:E2, "NotFound", 2, -1)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a2b222') - }) - - it('when there are no matching items, returns NotFound (all searchModes)', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, 1)'], - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, -1)'], - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, 2)'], - ['=XLOOKUP("t?b*", A5:E5, A5:E5, "NotFound", 2, -2)'], - ['a', 'axxb', 'a1b111', 'a2b222', 'x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A2'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A3'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A4'))).toEqual('NotFound') - }) - }) - - describe('for a vertical range', () => { - it('when searchMode = 1, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, 1)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = 2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, 2)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -2, returns the first matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, -2)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a1b111') - }) - - it('when searchMode = -1, returns the last matching item', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("a?b*", A2:A6, A2:A6, "NotFound", 2, -1)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('a2b222') - }) - - it('when there are no matching items, returns NotFound (all searchModes)', () => { - const engine = HyperFormula.buildFromArray([ - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, 1)'], - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, -1)'], - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, 2)'], - ['=XLOOKUP("t?b*", A5:A9, A5:A9, "NotFound", 2, -2)'], - ['a'], - ['axxb'], - ['a1b111'], - ['a2b222'], - ['x'], - ], { useColumnIndex: true }) - - expect(engine.getCellValue(adr('A1'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A2'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A3'))).toEqual('NotFound') - expect(engine.getCellValue(adr('A4'))).toEqual('NotFound') - }) - }) - }) - }) - - describe('acts similar to Microsoft Excel', () => { - /** - * Examples from - * https://support.microsoft.com/en-us/office/xlookup-function-b7fd680e-6d10-43e6-84f9-88eae8bf5929 - */ - - it('should find value in simple column range (official example 1)', () => { - const engine = HyperFormula.buildFromArray([ - ['China', 'CN'], - ['India', 'IN'], - ['United States', 'US'], - ['Indonesia', 'ID'], - ['France', 'FR'], - ['=XLOOKUP("Indonesia", A1:A5, B1:B5)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual('ID') - }) - - it('should find row range in table (official example 2)', () => { - const engine = HyperFormula.buildFromArray([ - ['8389', 'Dianne Pugh', 'Finance'], - ['4390', 'Ned Lanning', 'Marketing'], - ['8604', 'Margo Hendrix', 'Sales'], - ['8389', 'Dianne Pugh', 'Finance'], - ['4937', 'Earlene McCarty', 'Accounting'], - ['=XLOOKUP(A1, A2:A5, B2:C5)'], - ]) - - expect(engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A6'), 2, 1))).toEqual([['Dianne Pugh', 'Finance']]) - }) - - it('should find column range in table (official example 2, transposed)', () => { - const engine = HyperFormula.buildFromArray([ - ['8389', '4390', '8604', '8389', '4937'], - ['Dianne Pugh', 'Ned Lanning', 'Margo Hendrix', 'Dianne Pugh', 'Earlene McCarty'], - ['Finance', 'Marketing', 'Sales', 'Finance', 'Accounting'], - ['=XLOOKUP(A1, B1:E1, B2:E3)'], - [] - ]) - - expect(engine.getRangeValues(AbsoluteCellRange.spanFrom(adr('A4'), 1, 2))).toEqual([['Dianne Pugh'], ['Finance']]) - }) - - it('should find use if_not_found argument if not found (official example 3)', () => { - const engine = HyperFormula.buildFromArray([ - ['1234', 'Dianne Pugh', 'Finance'], - ['4390', 'Ned Lanning', 'Marketing'], - ['8604', 'Margo Hendrix', 'Sales'], - ['8389', 'Dianne Pugh', 'Finance'], - ['4937', 'Earlene McCarty', 'Accounting'], - ['=XLOOKUP(A1, A2:A5, B2:B5, "ID not found")'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual('ID not found') - }) - - it('example 4', () => { - const engine = HyperFormula.buildFromArray([ - ['10', 'a'], - ['20', 'b'], - ['30', 'c'], - ['40', 'd'], - ['50', 'e'], - ['=XLOOKUP(25, A1:A5, B1:B5, 0, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A6'))).toEqual('c') - }) - - it('nested xlookup function to perform both a vertical and horizontal match (official example 5)', () => { - const engine = HyperFormula.buildFromArray([ - ['Quarter', 'Gross profit', 'Net profit', 'Profit %'], - ['Qtr1', '=XLOOKUP(B1, $A4:$A12, XLOOKUP($A2, $B3:$F3, $B4:$F12))', '19342', '29.3'], - ['Income statement', 'Qtr1', 'Qtr2', 'Qtr3', 'Qtr4', 'Total'], - ['Total sales', '50000', '78200', '89500', '91200', '308950'], - ['Cost of sales', '25000', '42050', '59450', '60450', '186950'], - ['Gross profit', '25000', '36150', '30050', '30800', '122000'], - ['Depreciation', '899', '791', '202', '412', '2304'], - ['Interest', '513', '853', '150', '956', '2472'], - ['Earnings before tax', '23588', '34506', '29698', '29432', '117224'], - ['Tax', '4246', '6211', '5346', '5298', '21100'], - ['Net profit', '19342', '28295', '24352', '24134', '96124'], - ['Profit %', '29.3', '27.8', '23.4', '27.6', '26.9'], - ]) - - expect(engine.getCellValue(adr('B2'))).toEqual(25000) - }) - }) -}) diff --git a/test/unit/interpreter/function-xnpv.spec.ts b/test/unit/interpreter/function-xnpv.spec.ts deleted file mode 100644 index 4f04753350..0000000000 --- a/test/unit/interpreter/function-xnpv.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function XNPV', () => { - it('should return #NA! error with the wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(1,1)', '=XNPV(1, 1, 1, 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - /** - * Product #2 implements only Rate>0 (even though states in the documentation that Rate>-1). - */ - it('should accept Rate values that are greater than -1.', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(-1, A2:D2, A3:D3)', '=XNPV(2, A2:D2, A3:D3)', '=XNPV(-0.9, A2:D2, A3:D3)'], - [1, 2, 3, 4], - [1, 2, 3, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - expect(engine.getCellValue(adr('B1'))).toBeCloseTo(9.94002794561453, 6) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(10.1271695921145, 6) - }) - - it('should calculate the correct value', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(2%, 1, 1)'], - ['=XNPV(1, B2:C2, D2:E2)', 1, 2, 3, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(2.99620553730319, 6) - }) - - it('should round dates', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(1, B1:C1, D1:E1)', 1, 2, 3.1, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(2.99620553730319, 6) - }) - - it('only first date needs to be earliest', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(1, B1:E1, F1:I1)', 1, 2, 3, 4, 1, 4, 3, 2], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(9.9696766801485, 6) - }) - - it('should evaluate to #NUM! if values in range are not numbers', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(1, B1:C1, D1:E1)', 1, null, 3, null], - ['=XNPV(1, B2:C2, D2:E2)', 1, 2, 3.1, true], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberExpected)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberExpected)) - }) - - /** - * Product #1 tries to match the values in ranges. - */ - it('should evaluate to #NUM! if ranges are of different length', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(1, B1:C1, D1:F1)', 1, 2, 3, 4, 5], - ['=XNPV(1, B2:D2, E2:F2)', 1, 2, 3, 4, 5], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.EqualLength)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.EqualLength)) - }) - - it('should evaluate to #NUM! if dates are in wrong order', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(1, B1:C1, D1:E1)', 1, 2, 4, 3], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('should evaluate to #NUM! if dates are too small', () => { - const engine = HyperFormula.buildFromArray([ - ['=XNPV(1, B1:C1, D1:E1)', 1, 2, -1, 4], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) -}) diff --git a/test/unit/interpreter/function-xor.spec.ts b/test/unit/interpreter/function-xor.spec.ts deleted file mode 100644 index 6b9b325f3a..0000000000 --- a/test/unit/interpreter/function-xor.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function XOR', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=XOR(TRUE(), TRUE())'], - ['=XOR(TRUE(), FALSE())'], - ['=XOR(FALSE(), TRUE())'], - ['=XOR(FALSE(), FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toBe(true) - expect(engine.getCellValue(adr('A4'))).toBe(false) - }) - - it('at least one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=XOR()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('for one argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=XOR(TRUE())'], - ['=XOR(FALSE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(false) - }) - - it('use coercion #1', () => { - const engine = HyperFormula.buildFromArray([ - ['=XOR("TRUE")'], - ['=XOR(1)'], - ['=XOR(1, "foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('use coercion #2', () => { - const engine = HyperFormula.buildFromArray([ - ['=XOR(A4:B4)'], - ['=XOR(C4:D4)'], - ['=XOR(C4:D4, "foo")'], - ['TRUE', 1, 'foo', '=TRUE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('when no coercible to number arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=XOR("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.WrongType)) - }) - - it('returns TRUE iff odd number of TRUEs present', () => { - const engine = HyperFormula.buildFromArray([ - ['=XOR(TRUE(), TRUE(), TRUE())'], - ['=XOR(TRUE(), TRUE(), TRUE(), TRUE())'], - ['=XOR(TRUE(), TRUE(), TRUE(), TRUE(), TRUE())'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(false) - expect(engine.getCellValue(adr('A3'))).toBe(true) - }) - - it('if error in range found, returns first one in row-by-row order', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '=4/0'], - ['=FOOBAR()', '1'], - ['=XOR(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('works with ranges', () => { - const engine = HyperFormula.buildFromArray([ - ['0', '0'], - ['0', '1'], - ['=XOR(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(true) - }) - - it('is computed eagerly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=4/0'], - ['0', '1'], - ['=XOR(A1:B2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('when called with a range, ignores strings other than "true", "false" and ""', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', '=TRUE()', '=XOR(A1:B1)'], - ['foo', '=FALSE()', '=XOR(A2:B2)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(true) - expect(engine.getCellValue(adr('C2'))).toEqual(false) - }) -}) diff --git a/test/unit/interpreter/function-year.spec.ts b/test/unit/interpreter/function-year.spec.ts deleted file mode 100644 index 538485ec15..0000000000 --- a/test/unit/interpreter/function-year.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function YEAR', () => { - it('validate arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEAR(1, 2)'], - ['=YEAR()'], - ['=YEAR("foo")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('with numerical arguments', () => { - const engine = HyperFormula.buildFromArray([['=YEAR(0)', '=YEAR(2)', '=YEAR(43465)']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1899) - expect(engine.getCellValue(adr('B1'))).toEqual(1900) - expect(engine.getCellValue(adr('C1'))).toEqual(2018) - }) - - it('with string arguments', () => { - const engine = HyperFormula.buildFromArray([['=YEAR("31/12/1899")', '=YEAR("01/01/1900")', '=YEAR("31/12/2018")']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1899) - expect(engine.getCellValue(adr('B1'))).toEqual(1900) - expect(engine.getCellValue(adr('C1'))).toEqual(2018) - }) - - it('use datenumber coercion for 1st argument', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEAR(TRUE())'], - ['=YEAR(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1899) - expect(engine.getCellValue(adr('A2'))).toEqual(1899) - }) - - it('propagate errors', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEAR(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/function-yearfrac.spec.ts b/test/unit/interpreter/function-yearfrac.spec.ts deleted file mode 100644 index a8090ff043..0000000000 --- a/test/unit/interpreter/function-yearfrac.spec.ts +++ /dev/null @@ -1,132 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Function YEARFRAC', () => { - it('should not work for wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEARFRAC(1, 2, 3, 4)'], - ['=YEARFRAC(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('should not work for wrong type of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEARFRAC("foo", 1, TRUE())'], - ['=YEARFRAC(2, "bar")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('US mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEARFRAC("30/03/2020", "31/03/2020")'], - ['=YEARFRAC("28/02/2020", "29/02/2020")'], - ['=YEARFRAC("29/02/2020", "01/03/2020")'], - ['=YEARFRAC("28/02/2021", "01/03/2021")'], - ['=YEARFRAC("31/03/2020", "30/03/2020")'], - ['=YEARFRAC("29/02/2020", "28/02/2020")'], - ['=YEARFRAC("01/03/2020", "29/02/2020")'], - ['=YEARFRAC("01/03/2021", "28/02/2021")'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(1 / 360, 9) - }) - - it('actual/actual mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEARFRAC("01/01/2020", "02/01/2020", 1)'], - ['=YEARFRAC("01/01/2021", "02/01/2021", 1)'], - ['=YEARFRAC("28/02/2020", "01/03/2020", 1)'], - ['=YEARFRAC("28/02/2021", "01/03/2021", 1)'], - ['=YEARFRAC("31/12/2019", "01/03/2020", 1)'], - ['=YEARFRAC("31/12/2019", "29/02/2020", 1)'], - ['=YEARFRAC("31/12/2019", "28/02/2020", 1)'], - ['=YEARFRAC("01/01/2020", "01/01/2021", 1)'], - ['=YEARFRAC("01/01/2020", "02/01/2021", 1)'], - ['=YEARFRAC("01/01/2020", "01/01/2024", 1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1 / 366, 9) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1 / 365, 9) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(2 / 366, 9) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(1 / 365, 9) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(61 / 366, 9) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(60 / 366, 9) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(59 / 365, 9) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(1, 9) - expect(engine.getCellValue(adr('A9'))).toBeCloseTo(367 / 365.5, 9) - expect(engine.getCellValue(adr('A10'))).toBeCloseTo((366 + 365 + 365 + 365) / ((366 + 365 + 365 + 365 + 366) / 5), 9) - }) - - it('actual/360 mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEARFRAC("30/03/2020", "31/03/2020", 2)'], - ['=YEARFRAC("28/02/2020", "29/02/2020", 2)'], - ['=YEARFRAC("29/02/2020", "01/03/2020", 2)'], - ['=YEARFRAC("28/02/2021", "01/03/2021", 2)'], - ['=YEARFRAC("31/03/2020", "30/03/2021", 2)'], - ['=YEARFRAC("01/03/2021", "28/02/2020", 2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(364 / 360, 9) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(367 / 360, 9) - }) - - it('actual/365 mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEARFRAC("30/03/2020", "31/03/2020", 3)'], - ['=YEARFRAC("28/02/2020", "29/02/2020", 3)'], - ['=YEARFRAC("29/02/2020", "01/03/2020", 3)'], - ['=YEARFRAC("28/02/2021", "01/03/2021", 3)'], - ['=YEARFRAC("31/03/2020", "30/03/2021", 3)'], - ['=YEARFRAC("01/03/2021", "28/02/2020", 3)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1 / 365, 9) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1 / 365, 9) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(1 / 365, 9) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(1 / 365, 9) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(364 / 365, 9) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(367 / 365, 9) - }) - - it('EU mode', () => { - const engine = HyperFormula.buildFromArray([ - ['=YEARFRAC("30/03/2020", "31/03/2020", 4)'], - ['=YEARFRAC("28/02/2020", "29/02/2020", 4)'], - ['=YEARFRAC("29/02/2020", "01/03/2020", 4)'], - ['=YEARFRAC("28/02/2021", "01/03/2021", 4)'], - ['=YEARFRAC("31/03/2020", "30/03/2020", 4)'], - ['=YEARFRAC("29/02/2020", "28/02/2020", 4)'], - ['=YEARFRAC("01/03/2020", "29/02/2020", 4)'], - ['=YEARFRAC("01/03/2021", "28/02/2021", 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(2 / 360, 9) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(3 / 360, 9) - expect(engine.getCellValue(adr('A5'))).toEqual(0) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(1 / 360, 9) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(2 / 360, 9) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(3 / 360, 9) - }) -}) diff --git a/test/unit/interpreter/function-z.test.spec.ts b/test/unit/interpreter/function-z.test.spec.ts deleted file mode 100644 index 0ad16a48ea..0000000000 --- a/test/unit/interpreter/function-z.test.spec.ts +++ /dev/null @@ -1,65 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Z.TEST', () => { - it('validates number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=Z.TEST(1)'], - ['=Z.TEST(1, 2, 3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('works (no sigma)', () => { - const engine = HyperFormula.buildFromArray([ - ['=Z.TEST(A2:D2, 1)'], - [1, 2, 3, 4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0100683757751732, 6) - }) - - it('works (with sigma)', () => { - const engine = HyperFormula.buildFromArray([ - ['=Z.TEST(A2:D2, 1, 1)'], - [1, 2, 3, 4] - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0013498980316301, 6) - }) - - it('validates input', () => { - const engine = HyperFormula.buildFromArray([ - ['=Z.TEST(B1:C1, 1)', 1, null], - ['=Z.TEST(B2:C2, 1, 1)', null, null], - ['=Z.TEST(B3:C3, 1)', 1, 1], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO, ErrorMessage.TwoValues)) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.OneValue)) - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('doesnt do coercions, nonnumeric values are skipped', () => { - const engine = HyperFormula.buildFromArray([ - ['=Z.TEST(B1:E1, 1, 1)', null, 2, 3, 4], - ['=Z.TEST(B2:E2, 1, 1)', true, 2, 3, 4], - ]) - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.000266002752569605, 6) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.000266002752569605, 6) - }) - - it('propagates errors', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '10'], - ['=NA()', '50'], - ['3', '30'], - ['=Z.TEST(A1:B3, 1, 1)'], - ]) - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.NA)) - }) -}) diff --git a/test/unit/interpreter/matrix-plugin.spec.ts b/test/unit/interpreter/matrix-plugin.spec.ts deleted file mode 100644 index caf35103fd..0000000000 --- a/test/unit/interpreter/matrix-plugin.spec.ts +++ /dev/null @@ -1,301 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {ErrorMessage} from '../../../src/error-message' -import {MatrixPlugin} from '../../../src/interpreter/plugin/MatrixPlugin' -import {adr, detailedError, detailedErrorWithOrigin} from '../testUtils' - -describe('Matrix plugin', () => { - beforeAll(() => { - HyperFormula.registerFunctionPlugin(MatrixPlugin) - }) - - it('matrix multiplication', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['1', '2'], - ['3', '4'], - ['=MMULT(A1:B3,A4:B5)'], - ]) - - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(7) - expect(engine.getCellValue(adr('B6'))).toBeCloseTo(10) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(15) - expect(engine.getCellValue(adr('B7'))).toBeCloseTo(22) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(23) - expect(engine.getCellValue(adr('B8'))).toBeCloseTo(34) - }) - - it('matrix multiplication wrong size', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['1', '2', '3'], - ['4', '5', '6'], - ['7', '8', '9'], - ['=mmult(A1:B3,A4:C6)'], - ]) - - expect(engine.getCellValue(adr('A7'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ArrayDimensions)) - expect(engine.getCellValue(adr('B7'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ArrayDimensions)) - }) - - it('matrix multiplication with string in data', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=MMULT(A1:B2,A3:B4)'], - ['3', 'foo'], - ['1', '2', '=MMULT(A3:B4,A1:B2)'], - ['3', '4'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - expect(engine.getCellValue(adr('D2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - expect(engine.getCellValue(adr('C3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - expect(engine.getCellValue(adr('D4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - expect(engine.getCellValue(adr('C3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - expect(engine.getCellValue(adr('D4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - }) - - it('nested matrix multiplication', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['=MMULT(A1:B2, MMULT(A1:B2,A1:B2))'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(37) - expect(engine.getCellValue(adr('B3'))).toEqual(54) - expect(engine.getCellValue(adr('A4'))).toEqual(81) - expect(engine.getCellValue(adr('B4'))).toEqual(118) - }) - - it('mmult of other mmult', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=MMULT(A1:B2, A1:B2)'], - ['3', '4'], - ['=MMULT(A1:B2, C1:D2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(37) - expect(engine.getCellValue(adr('B3'))).toEqual(54) - expect(engine.getCellValue(adr('A4'))).toEqual(81) - expect(engine.getCellValue(adr('B4'))).toEqual(118) - }) - - it('mmult of a number', () => { - const engine = HyperFormula.buildFromArray([ - ['=MMULT(3, 4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(12) - }) - - it('mmult wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MMULT(0)', '=MMULT(0,0,0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('matrix multiplication by sumproduct', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['1', '2'], - ['3', '4'], - ['=SUMPRODUCT($A1:$B1,transpose(A$4:A$5))', '=SUMPRODUCT($A1:$B1,transpose(B$4:B$5))'], - ['=SUMPRODUCT($A2:$B2,transpose(A$4:A$5))', '=SUMPRODUCT($A2:$B2,transpose(B$4:B$5))'], - ['=SUMPRODUCT($A3:$B3,transpose(A$4:A$5))', '=SUMPRODUCT($A3:$B3,transpose(B$4:B$5))'], - ]) - - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(7) - expect(engine.getCellValue(adr('B6'))).toBeCloseTo(10) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(15) - expect(engine.getCellValue(adr('B7'))).toBeCloseTo(22) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(23) - expect(engine.getCellValue(adr('B8'))).toBeCloseTo(34) - }) - - it('matrix maxpool', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4', '5', '6'], - ['11', '12', '13', '14', '15', '16'], - ['21', '22', '23', '24', '25', '26'], - ['=maxpool(A1:F3,3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(23) - expect(engine.getCellValue(adr('B4'))).toBeCloseTo(26) - }) - - it('matrix maxpool non-numeric values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', 'bar', '3', '4', '5', '6'], - ['11', '12', '13', 'foo', '15', '16'], - ['21', '22', '23', '24', '25', '26'], - ['=maxpool(A1:F3,3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - }) - - it('matrix maxpool, custom stride', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4', '5', '6'], - ['11', '12', '13', '14', '15', '16'], - ['21', '22', '23', '24', '25', '26'], - ['28', '29', '30', '31', '32', '33'], - ['=maxpool(A1:F4,3,1)'], - ]) - - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(23) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(30) - expect(engine.getCellValue(adr('B5'))).toBeCloseTo(24) - expect(engine.getCellValue(adr('B6'))).toBeCloseTo(31) - expect(engine.getCellValue(adr('C5'))).toBeCloseTo(25) - expect(engine.getCellValue(adr('C6'))).toBeCloseTo(32) - expect(engine.getCellValue(adr('D5'))).toBeCloseTo(26) - expect(engine.getCellValue(adr('D6'))).toBeCloseTo(33) - }) - - it('maxpool wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MAXPOOL(0)', '=MAXPOOL(0, 0,0,0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('matrix medianpool on even square', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '1', '2', '1', '5'], - ['3', '4', '3', '7', '6', '7'], - ['=medianpool(A1:F2,2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(2.5) - expect(engine.getCellValue(adr('B3'))).toBeCloseTo(2.5) - expect(engine.getCellValue(adr('C3'))).toBeCloseTo(5.5) - }) - - it('medianpool wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=MEDIANPOOL(0)', '=MEDIANPOOL(0,0,0,0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('medianpool non-numeric values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', 'foo', '2', '1', '5'], - ['3', 'bar', '3', '7', '6', '7'], - ['=medianpool(A1:F2,2)'], - ]) - - expect(engine.getCellValue(adr('A3'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberRange)) - }) - - it('matrix medianpool on odd square', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1', '1'], // right shot from the beginning - ['1', '2', '3'], - ['3', '3', '3'], - - ['2', '2', '2'], // need one step to the left - ['3', '4', '6'], - ['10', '10', '10'], - - ['0', '0', '0'], // need one step to the right - ['4', '6', '7'], - ['8', '8', '8'], - - ['=medianpool(A1:C9,3)'], - ]) - - expect(engine.getCellValue(adr('A10'))).toBeCloseTo(2) - expect(engine.getCellValue(adr('A11'))).toBeCloseTo(4) - expect(engine.getCellValue(adr('A12'))).toBeCloseTo(6) - }) -}) - -describe('Function TRANSPOSE', () => { - it('transpose works', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=TRANSPOSE(A1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(1) - expect(engine.getCellValue(adr('B4'))).toBeCloseTo(3) - expect(engine.getCellValue(adr('C4'))).toBeCloseTo(5) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(2) - expect(engine.getCellValue(adr('B5'))).toBeCloseTo(4) - expect(engine.getCellValue(adr('C5'))).toBeCloseTo(6) - }) - - it('transpose works for scalar', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(1)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(1) - }) - - it('transpose returns error if argument evaluates to error', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE(4/0)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('transpose wrong number of arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRANSPOSE()', '=TRANSPOSE(C1:C2, D1:D2)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.NA, ErrorMessage.WrongArgNumber)) - }) - - it('transpose without braces', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ['5', '6'], - ['=TRANSPOSE(A1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toBe(1) - expect(engine.getCellValue(adr('A5'))).toBe(2) - expect(engine.getCellValue(adr('B4'))).toBe(3) - }) - - it('transpose any values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['foo', 'bar'], - ['=1/0', '=TRUE()'], - ['=TRANSPOSE(A1:B3)'], - ]) - - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(1) - expect(engine.getCellValue(adr('B4'))).toEqual('foo') - expect(engine.getCellValue(adr('C4'))).toEqual(detailedErrorWithOrigin(ErrorType.DIV_BY_ZERO, 'Sheet1!A3')) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(2) - expect(engine.getCellValue(adr('B5'))).toEqual('bar') - expect(engine.getCellValue(adr('C5'))).toEqual(true) - }) -}) diff --git a/test/unit/interpreter/nullvalue.spec.ts b/test/unit/interpreter/nullvalue.spec.ts deleted file mode 100644 index 31126052c6..0000000000 --- a/test/unit/interpreter/nullvalue.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {adr, detailedError} from '../testUtils' - -describe('EmptyValue tests', () => { - it('EmptyValue vs EmptyValue tests', () => { - const engine = HyperFormula.buildFromArray( - [ - [null, null, '=A1=B1', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1<>B1', '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=A1&B1', '=+A1', '=-A1', '=A1%'] - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(true) // EQUAL - expect(engine.getCellValue(adr('D1'))).toEqual(false) // GT - expect(engine.getCellValue(adr('E1'))).toEqual(false) // LT - expect(engine.getCellValue(adr('F1'))).toEqual(true) // GTE - expect(engine.getCellValue(adr('G1'))).toEqual(true) // LTE - expect(engine.getCellValue(adr('H1'))).toEqual(false) // NOT EQUAL - expect(engine.getCellValue(adr('I1'))).toEqual(0) // ADD - expect(engine.getCellValue(adr('J1'))).toEqual(0) // SUB - expect(engine.getCellValue(adr('K1'))).toEqual(0) // MULT - expect(engine.getCellValue(adr('L1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // DIV - expect(engine.getCellValue(adr('M1'))).toEqual(1) // EXP - expect(engine.getCellValue(adr('N1'))).toEqual('') // CONCAT - expect(engine.getCellValue(adr('O1'))).toBe(null) // UNARY PLUS - expect(engine.getCellValue(adr('P1'))).toEqual(0) // UNARY MINUS - expect(engine.getCellValue(adr('Q1'))).toEqual(0) // PERCENTAGE - }) - - it('Boolean vs EmptyValue tests', () => { - const engine = HyperFormula.buildFromArray( - [ - ['=TRUE()', null, '=A1=B1', '=A1>B1', '=A1=B1', '=A1<=B1', '=A1<>B1', '=A1+B1', '=A1-B1', '=A1*B1', '=A1/B1', '=A1^B1', '=A1&B1', '=+A1', '=-A1', '=A1%'] - ]) - expect(engine.getCellValue(adr('C1'))).toEqual(false) // EQUAL - expect(engine.getCellValue(adr('D1'))).toEqual(true) // GT - expect(engine.getCellValue(adr('E1'))).toEqual(false) // LT - expect(engine.getCellValue(adr('F1'))).toEqual(true) // GTE - expect(engine.getCellValue(adr('G1'))).toEqual(false) // LTE - expect(engine.getCellValue(adr('H1'))).toEqual(true) // NOT EQUAL - expect(engine.getCellValue(adr('I1'))).toEqual(1) // ADD - expect(engine.getCellValue(adr('J1'))).toEqual(1) // SUB - expect(engine.getCellValue(adr('K1'))).toEqual(0) // MULT - expect(engine.getCellValue(adr('L1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) // DIV - expect(engine.getCellValue(adr('M1'))).toEqual(1) // EXP - expect(engine.getCellValue(adr('N1'))).toEqual('TRUE') // CONCAT - expect(engine.getCellValue(adr('O1'))).toEqual(true) // UNARY PLUS - expect(engine.getCellValue(adr('P1'))).toEqual(-1) // UNARY MINUS - expect(engine.getCellValue(adr('Q1'))).toEqual(0.01) // PERCENTAGE - }) -}) diff --git a/test/unit/interpreter/number-literals.spec.ts b/test/unit/interpreter/number-literals.spec.ts deleted file mode 100644 index 0dad742e15..0000000000 --- a/test/unit/interpreter/number-literals.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Number literals', () => { - it('should work for integer', () => { - const engine = HyperFormula.buildFromArray([['="1" + 2']]) - expect(engine.getCellValue(adr('A1'))).toEqual(3) - }) - - it('should work for float with standard decimal separator', () => { - const engine = HyperFormula.buildFromArray([['="1.23" + 2']]) - expect(engine.getCellValue(adr('A1'))).toEqual(3.23) - }) - - it('should work for float with custom decimal separator', () => { - const engine = HyperFormula.buildFromArray([['="1,23" + 2']], new Config({ - decimalSeparator: ',', functionArgSeparator: ';' - })) - expect(engine.getCellValue(adr('A1'))).toEqual(3.23) - }) - - it('should work for number with thousand separator', () => { - const engine = HyperFormula.buildFromArray([['="1,000" + 2']], new Config({ - thousandSeparator: ',', functionArgSeparator: ';' - })) - expect(engine.getCellValue(adr('A1'))).toEqual(1002) - }) - - it('should work for number with another thousand separator', () => { - const engine = HyperFormula.buildFromArray([['="1 000" + 2']], new Config({ - thousandSeparator: ' ' - })) - expect(engine.getCellValue(adr('A1'))).toEqual(1002) - }) - - it('should work with thousand and decimal separator', () => { - const engine = HyperFormula.buildFromArray([['="1 000,2" + 2']], new Config({ - decimalSeparator: ',', thousandSeparator: ' ', functionArgSeparator: ';' - })) - expect(engine.getCellValue(adr('A1'))).toEqual(1002.2) - }) - - it('should work for multiple thousand separator in one literal', () => { - const engine = HyperFormula.buildFromArray([['="1 000 000" + 2']], new Config({ - thousandSeparator: ' ' - })) - expect(engine.getCellValue(adr('A1'))).toEqual(1000002) - }) - - it('should return value when thousand separator in literal does not match config', () => { - const engine = HyperFormula.buildFromArray([['="1 000" + 2']], new Config({ - thousandSeparator: ',', functionArgSeparator: ';' - })) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('should work for number with dot as thousand separator', () => { - const engine = HyperFormula.buildFromArray([['="1.000,3" + 2']], new Config({ - thousandSeparator: '.', decimalSeparator: ',', functionArgSeparator: ';' - })) - expect(engine.getCellValue(adr('A1'))).toEqual(1002.3) - }) -}) diff --git a/test/unit/interpreter/operator-concatenate.spec.ts b/test/unit/interpreter/operator-concatenate.spec.ts deleted file mode 100644 index d26e27d26e..0000000000 --- a/test/unit/interpreter/operator-concatenate.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {adr, detailedError} from '../testUtils' - -describe('Interpreter - concatenate operator', () => { - it('Ampersand with string arguments', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo"&"bar"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe('foobar') - }) - - it('Ampersand with cell address', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', '=A1&"bar"'], - ]) - - expect(engine.getCellValue(adr('B1'))).toBe('foobar') - }) - - it('Ampersand with number', () => { - const engine = HyperFormula.buildFromArray([ - ['=1&2'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe('12') - }) - - it('Ampersand with bool', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo"&TRUE()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe('fooTRUE') - }) - - it('Ampersand with null', () => { - const engine = HyperFormula.buildFromArray([ - ['="foo"&B1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe('foo') - }) - - it('Ampersand with error', () => { - const engine = HyperFormula.buildFromArray([ - ['=1/0', '=A1&TRUE()'], - ]) - - expect(engine.getCellValue(adr('B1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/operator-division.spec.ts b/test/unit/interpreter/operator-division.spec.ts deleted file mode 100644 index 5efcf9460c..0000000000 --- a/test/unit/interpreter/operator-division.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Operator DIVISION', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=9/3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3) - }) - - it('returns div when dividing by zero', () => { - const engine = HyperFormula.buildFromArray([ - ['=10/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['="9"/"3"'], - ['="foobar"/1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('pass error from left operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2/3'], - ['=FOOBAR()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('pass error from right operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=3/A2'], - ['=FOOBAR()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('pass error from left operand if both operands have error', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2/B2'], - ['=FOOBAR()', '=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['9'], - ['3'], - ['=10 / A1:A3'], - ['=A1:A3 / 10'], - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('Division propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)/2', '=2/(1/0)', '=(A1:B1)/(1/0)', '=(1/0)/(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/operator-minus.spec.ts b/test/unit/interpreter/operator-minus.spec.ts deleted file mode 100644 index 847abd9e7c..0000000000 --- a/test/unit/interpreter/operator-minus.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Operator MINUS', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=8-3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(5) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['="8"-"3"'], - ['="foobar"-1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(5) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('pass error from left operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2-3'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from right operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=3-A2'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from left operand if both operands have error', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2-B2'], - ['=FOOBAR()', '=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['8'], - ['3'], - ['=10 - A1:A3'], - ['=A1:A3 - 10'], - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('Minus propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)-2', '=2-(1/0)', '=(A1:B1)-(1/0)', '=(1/0)-(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/operator-percent.spec.ts b/test/unit/interpreter/operator-percent.spec.ts deleted file mode 100644 index 2e486bfa20..0000000000 --- a/test/unit/interpreter/operator-percent.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Percent operator', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=3%'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0.03) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['="3"%'], - ['="foobar"%'], - ['=TRUE()%'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0.03) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A3'))).toEqual(0.01) - }) - - it('pass reference', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2%'], - ['=42'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.42) - }) - - it('pass error', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2%'], - ['=FOOBAR()'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('works with other operator and coercion', () => { - const engine = HyperFormula.buildFromArray([['=TRUE()%*1']]) - - expect(engine.getCellValue(adr('A1'))).toEqual(0.01) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['9'], - ['3'], - ['=A1:A3%'], - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) -}) diff --git a/test/unit/interpreter/operator-plus.spec.ts b/test/unit/interpreter/operator-plus.spec.ts deleted file mode 100644 index 228d886bb7..0000000000 --- a/test/unit/interpreter/operator-plus.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Operator PLUS', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=2+3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(5) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['="2"+"3"'], - ['="foobar"+1'], - ['\'3'], - ['=A3+A3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(5) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - expect(engine.getCellValue(adr('A4'))).toEqual(6) - }) - - it('pass error from left operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2+3'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from right operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=3+A2'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from left operand if both operands have error', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2+B2'], - ['=FOOBAR()', '=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['=10 + A1:A3'], - ['=A1:A3 + 10'], - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('Plus propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - [0b1, '2', '=(1/0)+2', '=2+(1/0)', '=(A1:B1)+(1/0)', '=(1/0)+(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/operator-power.spec.ts b/test/unit/interpreter/operator-power.spec.ts deleted file mode 100644 index f2ca5b00b4..0000000000 --- a/test/unit/interpreter/operator-power.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Operator POWER', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=8^3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(512) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['="8"^"3"'], - ['="foobar"^1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(512) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('pass error from left operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2^3'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from right operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=3^A2'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from left operand if both operands have error', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2^B2'], - ['=FOOBAR()', '=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['8'], - ['3'], - ['=10 ^ A1:A3'], - ['=A1:A3 ^ 10'], - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('Power propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)^2', '=2^(1/0)', '=(A1:B1)^(1/0)', '=(1/0)^(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('NaN as a result', () => { - - const engine = HyperFormula.buildFromArray([ - ['01/02/1999', '02/02/1999', '=A1^B1'], - ['3.1415', '36193.2', '=A2^B2'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - }) - - it('negative base', () => { - const engine = HyperFormula.buildFromArray([ - ['', 2, -2], - [3, '=B1^A2', '=C1^A2'], - [3.5, '=B1^A3', '=C1^A3'], - ]) - - expect(engine.getCellValue(adr('B2'))).toBe(8) - expect(engine.getCellValue(adr('B3'))).toBeCloseTo(11.3137) - expect(engine.getCellValue(adr('C2'))).toBe(-8) - expect(engine.getCellValue(adr('C3'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.NaN)) - - }) -}) diff --git a/test/unit/interpreter/operator-times.spec.ts b/test/unit/interpreter/operator-times.spec.ts deleted file mode 100644 index 1c44649f5c..0000000000 --- a/test/unit/interpreter/operator-times.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Operator TIMES', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=8*3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(24) - }) - - it('no -0', () => { - const engine = HyperFormula.buildFromArray([ - ['=(-12)*0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['="8"*"3"'], - ['="foobar"*1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(24) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('pass error from left operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2*3'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from right operand', () => { - const engine = HyperFormula.buildFromArray([ - ['=3*A2'], - ['=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('pass error from left operand if both operands have error', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2*B2'], - ['=FOOBAR()', '=4/0'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=10 * A1:A3'], - ['8', '=A1:A3 * 10'], - ['3'], - ['=10 * A1:A3'], - ['=A1:A3 * 10'], - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('A5'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('Times propagates errors correctly', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '=(1/0)*2', '=2*(1/0)', '=(A1:B1)*(1/0)', '=(1/0)*(A1:B1)'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('E1'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - expect(engine.getCellValue(adr('F1'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) -}) diff --git a/test/unit/interpreter/operator-unary-minus.spec.ts b/test/unit/interpreter/operator-unary-minus.spec.ts deleted file mode 100644 index 9364e17698..0000000000 --- a/test/unit/interpreter/operator-unary-minus.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Unary operator MINUS', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=-3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-3) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=-"3"'], - ['=-"foobar"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(-3) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.NumberCoercion)) - }) - - it('pass error', () => { - const engine = HyperFormula.buildFromArray([ - ['=-B1', '=FOOBAR()'], - ['=-B2', '=1/0'], - - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['9'], - ['3'], - ['=-A1:A3'] - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('double unary plus', () => { - const engine = HyperFormula.buildFromArray([ - ['=--2'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/operator-unary-plus.spec.ts b/test/unit/interpreter/operator-unary-plus.spec.ts deleted file mode 100644 index 94410b764a..0000000000 --- a/test/unit/interpreter/operator-unary-plus.spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('Unary operator PLUS', () => { - it('works for obvious case', () => { - const engine = HyperFormula.buildFromArray([ - ['=+3'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(3) - }) - - it('use number coerce', () => { - const engine = HyperFormula.buildFromArray([ - ['=+"3"'], - ['=+"foobar"'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe('3') - expect(engine.getCellValue(adr('A2'))).toEqual('foobar') - }) - - it('pass error', () => { - const engine = HyperFormula.buildFromArray([ - ['=+B1', '=FOOBAR()'], - ['=+B2', '=1/0'], - - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.FunctionName('FOOBAR'))) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - }) - - it('range value results in VALUE error', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['9'], - ['3'], - ['=+A1:A3'], - ], {useArrayArithmetic: false}) - - expect(engine.getCellValue(adr('A4'))).toEqualError(detailedError(ErrorType.VALUE, ErrorMessage.ScalarExpected)) - }) - - it('string given by reference should return string with UNARY+', () => { - const engine = HyperFormula.buildFromArray([ - ['Liz'], - ['=+A1'] - ]) - expect(engine.getCellValue(adr('A2'))).toEqual('Liz') // UNARY PLUS value - }) - - it('double unary plus', () => { - const engine = HyperFormula.buildFromArray([ - ['=++2'], - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(2) - }) -}) diff --git a/test/unit/interpreter/paren-deps.spec.ts b/test/unit/interpreter/paren-deps.spec.ts deleted file mode 100644 index 48653216a0..0000000000 --- a/test/unit/interpreter/paren-deps.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('dependencies with parenthesis', () => { - it('should be collected when required', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(1)'], - ['=(A1)+((A3))'], - ['=SUM(1)'], - ]) - expect(engine.getCellValue(adr('A2'))).toEqual(2) - }) - - it('should not build ref for special function', () => { - const engine = HyperFormula.buildFromArray([ - ['=COLUMN((((A1))))'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) -}) diff --git a/test/unit/interpreter/precision.spec.ts b/test/unit/interpreter/precision.spec.ts deleted file mode 100644 index 2ceecfe19e..0000000000 --- a/test/unit/interpreter/precision.spec.ts +++ /dev/null @@ -1,290 +0,0 @@ -import {HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('Imprecise comparisons', () => { - - it('less-than', () => { - const chunk1 = '.0000000001' - const chunk2 = '.00000000000005' - const engine = HyperFormula.buildFromArray([ - ['=1<1' + chunk1, '=1<1' + chunk2], - ['=1' + chunk1 + '<1', '=1' + chunk2 + '<1'], - ['=-1' + chunk1 + '<-1', '=-1' + chunk2 + '<-1'], - ['=-1<-1' + chunk1, '=-1<-1' + chunk2], - ['=0<0' + chunk1, '=0<0' + chunk2], - ['=0' + chunk1 + '<0', '=0' + chunk2 + '<0'], - ['=-0' + chunk1 + '<0', '=-0' + chunk2 + '<0'], - ['=0<-0' + chunk1, '=0<-0' + chunk2], - ], {smartRounding: true}) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('A2'))).toBe(false) - expect(engine.getCellValue(adr('B2'))).toBe(false) - expect(engine.getCellValue(adr('A3'))).toBe(true) - expect(engine.getCellValue(adr('B3'))).toBe(false) - expect(engine.getCellValue(adr('A4'))).toBe(false) - expect(engine.getCellValue(adr('B4'))).toBe(false) - expect(engine.getCellValue(adr('A5'))).toBe(true) - expect(engine.getCellValue(adr('B5'))).toBe(true) - expect(engine.getCellValue(adr('A6'))).toBe(false) - expect(engine.getCellValue(adr('B6'))).toBe(false) - expect(engine.getCellValue(adr('A7'))).toBe(true) - expect(engine.getCellValue(adr('B7'))).toBe(true) - expect(engine.getCellValue(adr('A8'))).toBe(false) - expect(engine.getCellValue(adr('B8'))).toBe(false) - }) - - it('greater-than', () => { - const chunk1 = '.0000000001' - const chunk2 = '.0000000000001' - const engine = HyperFormula.buildFromArray([ - ['=1>1' + chunk1, '=1>1' + chunk2], - ['=1' + chunk1 + '>1', '=1' + chunk2 + '>1'], - ['=-1' + chunk1 + '>-1', '=-1' + chunk2 + '>-1'], - ['=-1>-1' + chunk1, '=-1>-1' + chunk2], - ['=0>0' + chunk1, '=0>0' + chunk2], - ['=0' + chunk1 + '>0', '=0' + chunk2 + '>0'], - ['=-0' + chunk1 + '>0', '=-0' + chunk2 + '>0'], - ['=0>-0' + chunk1, '=0>-0' + chunk2], - ], {smartRounding: true}) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(false) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('B2'))).toBe(false) - expect(engine.getCellValue(adr('A3'))).toBe(false) - expect(engine.getCellValue(adr('B3'))).toBe(false) - expect(engine.getCellValue(adr('A4'))).toBe(true) - expect(engine.getCellValue(adr('B4'))).toBe(false) - expect(engine.getCellValue(adr('A5'))).toBe(false) - expect(engine.getCellValue(adr('B5'))).toBe(false) - expect(engine.getCellValue(adr('A6'))).toBe(true) - expect(engine.getCellValue(adr('B6'))).toBe(true) - expect(engine.getCellValue(adr('A7'))).toBe(false) - expect(engine.getCellValue(adr('B7'))).toBe(false) - expect(engine.getCellValue(adr('A8'))).toBe(true) - expect(engine.getCellValue(adr('B8'))).toBe(true) - }) - - it('greater-equal', () => { - const chunk1 = '.0000000001' - const chunk2 = '.0000000000001' - const engine = HyperFormula.buildFromArray([ - ['=1>=1' + chunk1, '=1>=1' + chunk2], - ['=1' + chunk1 + '>=1', '=1' + chunk2 + '>=1'], - ['=-1' + chunk1 + '>=-1', '=-1' + chunk2 + '>=-1'], - ['=-1>=-1' + chunk1, '=-1>=-1' + chunk2], - ['=0>=0' + chunk1, '=0>=0' + chunk2], - ['=0' + chunk1 + '>=0', '=0' + chunk2 + '>=0'], - ['=-0' + chunk1 + '>=0', '=-0' + chunk2 + '>=0'], - ['=0>=-0' + chunk1, '=0>=-0' + chunk2], - ], {smartRounding: true}) - - expect(engine.getCellValue(adr('A1'))).toBe(false) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(true) - expect(engine.getCellValue(adr('B2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toBe(false) - expect(engine.getCellValue(adr('B3'))).toBe(true) - expect(engine.getCellValue(adr('A4'))).toBe(true) - expect(engine.getCellValue(adr('B4'))).toBe(true) - expect(engine.getCellValue(adr('A5'))).toBe(false) - expect(engine.getCellValue(adr('B5'))).toBe(false) - expect(engine.getCellValue(adr('A6'))).toBe(true) - expect(engine.getCellValue(adr('B6'))).toBe(true) - expect(engine.getCellValue(adr('A7'))).toBe(false) - expect(engine.getCellValue(adr('B7'))).toBe(false) - expect(engine.getCellValue(adr('A8'))).toBe(true) - expect(engine.getCellValue(adr('B8'))).toBe(true) - }) - - it('less-equal', () => { - const chunk1 = '.0000000001' - const chunk2 = '.0000000000001' - const engine = HyperFormula.buildFromArray([ - ['=1<=1' + chunk1, '=1<=1' + chunk2], - ['=1' + chunk1 + '<=1', '=1' + chunk2 + '<=1'], - ['=-1' + chunk1 + '<=-1', '=-1' + chunk2 + '<=-1'], - ['=-1<=-1' + chunk1, '=-1<=-1' + chunk2], - ['=0<=0' + chunk1, '=0<=0' + chunk2], - ['=0' + chunk1 + '<=0', '=0' + chunk2 + '<=0'], - ['=-0' + chunk1 + '<=0', '=-0' + chunk2 + '<=0'], - ['=0<=-0' + chunk1, '=0<=-0' + chunk2], - ], {smartRounding: true}) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(true) - expect(engine.getCellValue(adr('A2'))).toBe(false) - expect(engine.getCellValue(adr('B2'))).toBe(true) - expect(engine.getCellValue(adr('A3'))).toBe(true) - expect(engine.getCellValue(adr('B3'))).toBe(true) - expect(engine.getCellValue(adr('A4'))).toBe(false) - expect(engine.getCellValue(adr('B4'))).toBe(true) - expect(engine.getCellValue(adr('A5'))).toBe(true) - expect(engine.getCellValue(adr('B5'))).toBe(true) - expect(engine.getCellValue(adr('A6'))).toBe(false) - expect(engine.getCellValue(adr('B6'))).toBe(false) - expect(engine.getCellValue(adr('A7'))).toBe(true) - expect(engine.getCellValue(adr('B7'))).toBe(true) - expect(engine.getCellValue(adr('A8'))).toBe(false) - expect(engine.getCellValue(adr('B8'))).toBe(false) - }) -}) - -describe('Snap to zero', () => { - - it('minus', () => { - const chunk1 = '.0000000001' - const chunk2 = '.0000000000001' - const engine = HyperFormula.buildFromArray([ - ['=1-1' + chunk1, '=1-1' + chunk2], - ['=1' + chunk1 + '-1', '=1' + chunk2 + '-1'], - ['=-1' + chunk1 + '--1', '=-1' + chunk2 + '--1'], - ['=-1--1' + chunk1, '=-1--1' + chunk2], - ['=0-0' + chunk1, '=0-0' + chunk2], - ['=0' + chunk1 + '-0', '=0' + chunk2 + '-0'], - ['=-0' + chunk1 + '-0', '=-0' + chunk2 + '-0'], - ['=0--0' + chunk1, '=0--0' + chunk2], - ], {smartRounding: true}) - - expect(engine.dependencyGraph.getCellValue(adr('A1'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B1'))).toEqual(0) - expect(engine.dependencyGraph.getCellValue(adr('A2'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B2'))).toEqual(0) - expect(engine.dependencyGraph.getCellValue(adr('A3'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B3'))).toEqual(0) - expect(engine.dependencyGraph.getCellValue(adr('A4'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B4'))).toEqual(0) - expect(engine.dependencyGraph.getCellValue(adr('A5'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B5'))).toBeCloseTo(0.0000000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('A6'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B6'))).toBeCloseTo(0.0000000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('A7'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B7'))).toBeCloseTo(0.0000000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('A8'))).toBeCloseTo(0.0000000001, 5) - expect(engine.dependencyGraph.getCellValue(adr('B8'))).toBeCloseTo(0.0000000000001, 5) - }) - - it('plus', () => { - const chunk1 = '.0000000001' - const chunk2 = '.0000000000001' - const engine = HyperFormula.buildFromArray([ - ['=1+-1' + chunk1, '=1+-1' + chunk2], - ['=1' + chunk1 + '+-1', '=1' + chunk2 + '+-1'], - ['=-1' + chunk1 + '+1', '=-1' + chunk2 + '+1'], - ['=-1+1' + chunk1, '=-1+1' + chunk2], - ['=0+-0' + chunk1, '=0+-0' + chunk2], - ['=0' + chunk1 + '+-0', '=0' + chunk2 + '+-0'], - ['=-0' + chunk1 + '+-0', '=-0' + chunk2 + '+-0'], - ['=0+0' + chunk1, '=0+0' + chunk2], - ], {smartRounding: true}) - - expect(engine.getCellValue(adr('A1'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B2'))).toEqual(0) - expect(engine.getCellValue(adr('A3'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B3'))).toEqual(0) - expect(engine.getCellValue(adr('A4'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B4'))).toEqual(0) - expect(engine.getCellValue(adr('A5'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B5'))).toBeCloseTo(0.0000000000001, 5) - expect(engine.getCellValue(adr('A6'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B6'))).toBeCloseTo(0.0000000000001, 5) - expect(engine.getCellValue(adr('A7'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B7'))).toBeCloseTo(0.0000000000001, 5) - expect(engine.getCellValue(adr('A8'))).toBeCloseTo(0.0000000001, 5) - expect(engine.getCellValue(adr('B8'))).toBeCloseTo(0.0000000000001, 5) - }) -}) - -describe('Value-fixed', () => { - it('should correctly calculate 0.2 + 0.1 as 0.3', () => { - const engine = HyperFormula.buildFromArray([ - ['=0.2+0.1'], - ], {smartRounding: true}) - - expect(engine.getCellValue(adr('A1'))).toBe(0.3) - }) -}) - -describe('tests', () => { - it('addition of small numbers with smartRounding #1', () => { - const engine = HyperFormula.buildFromArray([ - ['0.000123456789', '1', '=A1+B1'], - ], {smartRounding: true}) - - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(1.000123456789, 10) - }) - - it('addition of small numbers with smartRounding #2', () => { - const engine = HyperFormula.buildFromArray([ - ['0.000123456789', '1', '=A1+B1'], - ], {smartRounding: true, precisionRounding: 9}) - - expect(engine.getCellValue(adr('C1'))).toEqual(1.000123457) //as GS and E - }) -}) - -describe('internal rounding', () => { - it('Precision accumulates', () => { - const engine = HyperFormula.buildFromArray([ - ['', 'Revenue', '', '1000', '=D1*(1+E2)', '=E1*(1+F2)', '=F1*(1+G2)', '=G1*(1+H2)', '=H1*(1+I2)', '=I1*(1+J2)', '=J1*(1+K2)', '=K1*(1+L2)', '=L1*(1+M2)', '=M1*(1+N2)'], - ['', '% Growth', '', '', '.100000000000000', '=E2', '=F2', '=G2', '=H2', '=I2', '=J2', '=K2', '=L2', '=M2'] - ]) - expect(engine.getSheetValues(0)).toEqual([ - // eslint-disable-next-line @typescript-eslint/no-loss-of-precision - ['', 'Revenue', '', 1000.000000000000000, 1100.000000000000000, 1210.000000000000000, 1331.000000000000000, 1464.100000000000000, 1610.510000000000000, 1771.561000000000000, 1948.717100000000000, 2143.588810000000000, 2357.947691000000000, 2593.742460100000000], - ['', '% Growth', '', '', .100000000000000, .100000000000000, .100000000000000, .100000000000000, .100000000000000, .100000000000000, .100000000000000, .100000000000000, .100000000000000, .100000000000000] - ]) - }) -}) - -describe('number of leading digits', () => { - it('rounding extensive test', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '0.33333333333333300000', '=A1/3'], - ['10', '3.33333333333333000000', '=A2/3'], - ['100', '33.33333333333330000000', '=A3/3'], - ['1000', '333.33333333333300000000', '=A4/3'], - ['10000', '3333.33333333333000000000', '=A5/3'], - ['100000', '33333.33333333330000000000', '=A6/3'], - ['1000000', '333333.33333333300000000000', '=A7/3'], - ['10000000', '3333333.33333333000000000000', '=A8/3'], - ['100000000', '33333333.33333330000000000000', '=A9/3'], - ['1000000000', '333333333.33333300000000000000', '=A10/3'], - ['10000000000', '3333333333.33333000000000000000', '=A11/3'], - ['100000000000', '33333333333.33330000000000000000', '=A12/3'], - ['1000000000000', '333333333333.33300000000000000000', '=A13/3'], - ['10000000000000', '3333333333333.33000000000000000000', '=A14/3'], - ['100000000000000', '33333333333333.30000000000000000000', '=A15/3'], - ['1000000000000000', '333333333333333.00000000000000000000', '=A16/3'], - ['10000000000000000', '3333333333333330.00000000000000000000', '=A17/3'], - ['100000000000000000', '33333333333333300.00000000000000000000', '=A18/3'], - ['1000000000000000000', '333333333333333000.00000000000000000000', '=A19/3'], - ['10000000000000000000', '3333333333333330000.00000000000000000000', '=A20/3'], - ]) - - expect(engine.getCellValue(adr('C1'))).toEqual(engine.getCellValue(adr('B1'))) - expect(engine.getCellValue(adr('C2'))).toEqual(engine.getCellValue(adr('B2'))) - expect(engine.getCellValue(adr('C3'))).toEqual(engine.getCellValue(adr('B3'))) - expect(engine.getCellValue(adr('C4'))).toEqual(engine.getCellValue(adr('B4'))) - expect(engine.getCellValue(adr('C5'))).toEqual(engine.getCellValue(adr('B5'))) - expect(engine.getCellValue(adr('C6'))).toEqual(engine.getCellValue(adr('B6'))) - expect(engine.getCellValue(adr('C7'))).toEqual(engine.getCellValue(adr('B7'))) - expect(engine.getCellValue(adr('C8'))).toEqual(engine.getCellValue(adr('B8'))) - expect(engine.getCellValue(adr('C9'))).toEqual(engine.getCellValue(adr('B9'))) - expect(engine.getCellValue(adr('C10'))).toEqual(engine.getCellValue(adr('B10'))) - expect(engine.getCellValue(adr('C11'))).toEqual(engine.getCellValue(adr('B11'))) - expect(engine.getCellValue(adr('C12'))).toEqual(engine.getCellValue(adr('B12'))) - expect(engine.getCellValue(adr('C13'))).toEqual(engine.getCellValue(adr('B13'))) - expect(engine.getCellValue(adr('C14'))).toEqual(engine.getCellValue(adr('B14'))) - expect(engine.getCellValue(adr('C15'))).toEqual(engine.getCellValue(adr('B15'))) - expect(engine.getCellValue(adr('C16'))).toEqual(engine.getCellValue(adr('B16'))) - expect(engine.getCellValue(adr('C17'))).toEqual(engine.getCellValue(adr('B17'))) - expect(engine.getCellValue(adr('C18'))).toEqual(engine.getCellValue(adr('B18'))) - expect(engine.getCellValue(adr('C19'))).toEqual(engine.getCellValue(adr('B19'))) - expect(engine.getCellValue(adr('C20'))).toEqual(engine.getCellValue(adr('B20'))) - }) -}) diff --git a/test/unit/interpreter/scalar.spec.ts b/test/unit/interpreter/scalar.spec.ts deleted file mode 100644 index bd7b74c84f..0000000000 --- a/test/unit/interpreter/scalar.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {ErrorType} from '../../../src' -import {CellError} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {DateTimeHelper} from '../../../src/DateTimeHelper' -import {ArithmeticHelper} from '../../../src/interpreter/ArithmeticHelper' -import {NumberLiteralHelper} from '../../../src/NumberLiteralHelper' - -describe('nonstrictadd', () => { - const config = new Config() - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateTimeHelper, numberLiteralsHelper) - it('adds', () => { - expect(arithmeticHelper.nonstrictadd(2, 3)).toEqual(5) - }) - - it('return error of right operand', () => { - expect(arithmeticHelper.nonstrictadd(2, new CellError(ErrorType.DIV_BY_ZERO))).toEqual(new CellError(ErrorType.DIV_BY_ZERO)) - }) - - it('return error of left operand if both present', () => { - expect(arithmeticHelper.nonstrictadd(new CellError(ErrorType.NA), new CellError(ErrorType.DIV_BY_ZERO))).toEqual(new CellError(ErrorType.NA)) - }) - - it('ignores non-numerics', () => { - expect(arithmeticHelper.nonstrictadd('foo', 5)).toEqual(5) - expect(arithmeticHelper.nonstrictadd(5, 'foo')).toEqual(5) - expect(arithmeticHelper.nonstrictadd('bar', 'foo')).toEqual(0) - }) - - it('returns 0 if only non-numerics', () => { - expect(arithmeticHelper.nonstrictadd('bar', 'foo')).toEqual(0) - }) -}) diff --git a/test/unit/interpreter/separate-cache.spec.ts b/test/unit/interpreter/separate-cache.spec.ts deleted file mode 100644 index d9ac53ce7f..0000000000 --- a/test/unit/interpreter/separate-cache.spec.ts +++ /dev/null @@ -1,17 +0,0 @@ -import {HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('numeric aggreagtion functions', () => { - it('should use separate caches', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 5, 10, 20], - ['=MIN(A1:E1)', '=MAX(A1:E1)', '=SUM(A1:E1)', '=SUMSQ(A1:E1)', '=AVERAGE(A1:E1)'], - ['=MIN(A1:E1)', '=MAX(A1:E1)', '=SUM(A1:E1)', '=SUMSQ(A1:E1)', '=AVERAGE(A1:E1)'], - ]) - expect(engine.getCellValue(adr('A3'))).toEqual(1) - expect(engine.getCellValue(adr('B3'))).toEqual(20) - expect(engine.getCellValue(adr('C3'))).toEqual(38) - expect(engine.getCellValue(adr('D3'))).toEqual(530) - expect(engine.getCellValue(adr('E3'))).toEqual(7.6) - }) -}) diff --git a/test/unit/interpreter/string-cmp.spec.ts b/test/unit/interpreter/string-cmp.spec.ts deleted file mode 100644 index 24df280063..0000000000 --- a/test/unit/interpreter/string-cmp.spec.ts +++ /dev/null @@ -1,144 +0,0 @@ -import {HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('string comparison', () => { - it('comparison default', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'A', '=A1>B1'], - ['aa', 'AA', '=A2>B2'], - ['aA', 'aa', '=A3>B3'], - ['Aa', 'aa', '=A4>B4'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) - - it('works with localeLang = "en-US"', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'A', '=A1>B1'], - ['aa', 'AA', '=A2>B2'], - ['aA', 'aa', '=A3>B3'], - ['Aa', 'aa', '=A4>B4'], - ], { localeLang: 'en-US' }) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) - - it('accents default', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'ä', '=A1>B1'], - ['áá', 'ää', '=A2>B2'], - ['ää', 'ĄĄ', '=A3>B3'], - ['ää', 'ZZ', '=A4>B4'], - ]) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) - - it('accents sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['Ą', 'ą', '=A1>B1'], - ['ää', 'áá', '=A2>B2'], - ['ää', 'ĄĄ', '=A3>B3'], - ['ää', 'ŹŹ', '=A4>B4'], - ], {accentSensitive: true}) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(true) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) - - it('accents+case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['Ą', 'ą', '=A1>B1'], - ['áá', 'ää', '=A2>B2'], - ['ää', 'ĄĄ', '=A3>B3'], - ['ää', 'ŹŹ', '=A4>B4'], - ], {accentSensitive: true, caseSensitive: true}) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) - - it('accents+case sensitive, reverse order', () => { - const engine = HyperFormula.buildFromArray([ - ['Ą', 'ą', '=A1>B1'], - ['áá', 'ää', '=A2>B2'], - ['ää', 'ĄĄ', '=A3>B3'], - ['ää', 'ŹŹ', '=A4>B4'], - ], {accentSensitive: true, caseSensitive: true, caseFirst: 'upper'}) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) - - it('accents lang', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'ä', '=A1>B1'], - ['aa', 'ää', '=A2>B2'], - ['ää', 'ĄĄ', '=A3>B3'], - ['ää', 'ZZ', '=A4>B4'], - ], {localeLang: 'sv', accentSensitive: true}) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(true) - expect(engine.getCellValue(adr('C4'))).toBe(true) - }) - - it('comparison case sensitive', () => { - const engine = HyperFormula.buildFromArray([ - ['ą', 'A', '=A1>B1'], - ['aa', 'AA', '=A2>B2'], - ['aA', 'aa', '=A3>B3'], - ['Aa', 'aa', '=A4>B4'], - ], {caseSensitive: true}) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(true) - expect(engine.getCellValue(adr('C4'))).toBe(true) - }) - - it('comparison case sensitive, reverse order', () => { - const engine = HyperFormula.buildFromArray([ - ['ą', 'A', '=A1>B1'], - ['aa', 'AA', '=A2>B2'], - ['aA', 'aa', '=A3>B3'], - ['Aa', 'aa', '=A4>B4'], - ], {caseSensitive: true, caseFirst: 'upper'}) - - expect(engine.getCellValue(adr('C1'))).toBe(true) - expect(engine.getCellValue(adr('C2'))).toBe(true) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) - - it('comparison ignore punctuation', () => { - const engine = HyperFormula.buildFromArray([ - ['a', 'A,A,A', '=A1>B1'], - ['aa', '...AA', '=A2>B2'], - ['aA', ';;;;aa', '=A3>B3'], - ['Aa', '????aa', '=A4>B4'], - ], {ignorePunctuation: true}) - - expect(engine.getCellValue(adr('C1'))).toBe(false) - expect(engine.getCellValue(adr('C2'))).toBe(false) - expect(engine.getCellValue(adr('C3'))).toBe(false) - expect(engine.getCellValue(adr('C4'))).toBe(false) - }) -}) diff --git a/test/unit/licence.spec.ts b/test/unit/licence.spec.ts deleted file mode 100644 index 2deaf5dbbe..0000000000 --- a/test/unit/licence.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {ErrorMessage} from '../../src/error-message' -import {adr, detailedError} from './testUtils' - -describe('Wrong licence', () => { - it('eval', () => { - const engine = HyperFormula.buildFromArray([['=TRUE()', null, 1, '=A(']], {licenseKey: ''}) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.LIC, ErrorMessage.LicenseKey('missing'))) - expect(engine.getCellValue(adr('B1'))).toEqual(null) - expect(engine.getCellValue(adr('C1'))).toEqual(1) - expect(engine.getCellValue(adr('D1'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - - it('serialization', () => { - const engine = HyperFormula.buildFromArray([['=TRUE()', null, 1, '=A(']], {licenseKey: ''}) - expect(engine.getSheetSerialized(0)).toEqual([['=TRUE()', null, 1, '=A(']]) - }) -}) diff --git a/test/unit/matchers.spec.ts b/test/unit/matchers.spec.ts deleted file mode 100644 index 6e3cdd8d36..0000000000 --- a/test/unit/matchers.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import {DetailedCellError} from '../../src' -import {ArraySize} from '../../src/ArraySize' -import {CellError, ErrorType} from '../../src/Cell' -import {FormulaVertex} from '../../src/DependencyGraph/FormulaVertex' -import {buildNumberAst} from '../../src/parser/Ast' -import {adr} from './testUtils' - -describe('Matchers', () => { - it('should compare two simple values', () => { - expect(1).toEqualError(1) - expect(1).not.toEqualError(2) - }) - - it('should compare two cell errors ignoring vertices', () => { - function dummyFormulaVertex(): FormulaVertex { - return FormulaVertex.fromAst(buildNumberAst(1), adr('A1'), ArraySize.scalar(), 0) - } - - expect( - new CellError(ErrorType.ERROR, '', dummyFormulaVertex()) - ).toEqualError( - new CellError(ErrorType.ERROR, '') - ) - - expect( - new CellError(ErrorType.ERROR, 'a', dummyFormulaVertex()) - ).not.toEqualError( - new CellError(ErrorType.ERROR, 'b', dummyFormulaVertex()) - ) - - expect( - new CellError(ErrorType.NA, '', dummyFormulaVertex()) - ).not.toEqualError( - new CellError(ErrorType.ERROR, '', dummyFormulaVertex()) - ) - }) - - it('compare two detailed errors ignoring addresses', () => { - expect( - new DetailedCellError(new CellError(ErrorType.ERROR), '') - ).toEqualError( - new DetailedCellError(new CellError(ErrorType.ERROR), '', 'A1') - ) - - expect( - new DetailedCellError(new CellError(ErrorType.ERROR), 'a') - ).not.toEqualError( - new DetailedCellError(new CellError(ErrorType.ERROR), '', 'A1') - ) - }) - - it('should compare two ad-hoc objects ignoring addresses', () => { - expect( - {type: ErrorType.ERROR, message: '', address: adr('A1')} - ).toEqualError( - {type: ErrorType.ERROR, message: '', address: undefined} - ) - }) -}) diff --git a/test/unit/matrix-mapping.spec.ts b/test/unit/matrix-mapping.spec.ts deleted file mode 100644 index d03f5d670f..0000000000 --- a/test/unit/matrix-mapping.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {ArraySize} from '../../src/ArraySize' -import {ArrayMapping, ArrayFormulaVertex} from '../../src/DependencyGraph' -import {buildNumberAst} from '../../src/parser/Ast' -import {adr} from './testUtils' - -describe('MatrixMapping', () => { - it('should be empty', () => { - const matrixMapping = new ArrayMapping() - - expect(matrixMapping.count()).toEqual(0) - }) - it('should set matrix', () => { - const matrixMapping = new ArrayMapping() - - const vertex = new ArrayFormulaVertex(buildNumberAst(1), adr('A1'), new ArraySize(2, 2)) - const range = AbsoluteCellRange.spanFrom(adr('A1'), 2, 2) - matrixMapping.setArray(range, vertex) - - expect(matrixMapping.count()).toEqual(1) - expect(matrixMapping.getArray(range)).toEqual(vertex) - }) - - it('should answer some questions', () => { - const matrixMapping = new ArrayMapping() - const vertex = new ArrayFormulaVertex(buildNumberAst(1), adr('B2'), new ArraySize(2, 2)) - const range = AbsoluteCellRange.spanFrom(adr('B2'), 2, 2) - matrixMapping.setArray(range, vertex) - - expect(matrixMapping.isFormulaArrayInRow(0, 0)).toBe(false) - expect(matrixMapping.isFormulaArrayInRow(0, 1)).toBe(true) - expect(matrixMapping.isFormulaArrayAtAddress(adr('A1'))).toBe(false) - expect(matrixMapping.isFormulaArrayAtAddress(adr('B2'))).toBe(true) - expect(matrixMapping.isFormulaArrayInRange(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1))).toEqual(false) - expect(matrixMapping.isFormulaArrayInRange(AbsoluteCellRange.spanFrom(adr('B1'), 1, 2))).toEqual(true) - expect(matrixMapping.isFormulaArrayInRange(AbsoluteCellRange.spanFrom(adr('A2'), 2, 1))).toEqual(true) - expect(matrixMapping.isFormulaArrayInColumn(0, 0)).toEqual(false) - expect(matrixMapping.isFormulaArrayInColumn(0, 1)).toEqual(true) - expect(matrixMapping.isFormulaArrayInRow(0, 0)).toEqual(false) - expect(matrixMapping.isFormulaArrayInRow(0, 1)).toEqual(true) - }) - - it('should move matrices below row', () => { - const matrixMapping = new ArrayMapping() - const vertex1 = new ArrayFormulaVertex(buildNumberAst(1), adr('B1'), new ArraySize(2, 2)) - const range1 = AbsoluteCellRange.spanFrom(adr('B1'), 2, 2) - const vertex2 = new ArrayFormulaVertex(buildNumberAst(1), adr('D2'), new ArraySize(2, 2)) - const range2 = AbsoluteCellRange.spanFrom(adr('D2'), 2, 2) - matrixMapping.setArray(range1, vertex1) - matrixMapping.setArray(range2, vertex2) - - matrixMapping.moveArrayVerticesAfterRowByRows(0, 0, 2) - - expect(matrixMapping.getArrayByCorner(range1.start)).toBeUndefined() - expect(matrixMapping.getArrayByCorner(range2.start)).toBeUndefined() - expect(matrixMapping.getArrayByCorner(adr('B3'))).toEqual(vertex1) - expect(matrixMapping.getArrayByCorner(adr('D4'))).toEqual(vertex2) - }) -}) diff --git a/test/unit/matrix-size-check.spec.ts b/test/unit/matrix-size-check.spec.ts deleted file mode 100644 index 0b422062dd..0000000000 --- a/test/unit/matrix-size-check.spec.ts +++ /dev/null @@ -1,195 +0,0 @@ -import {ArraySize, ArraySizePredictor} from '../../src/ArraySize' -import {Config} from '../../src/Config' -import {FunctionRegistry} from '../../src/interpreter/FunctionRegistry' -import {Interpreter} from '../../src/interpreter/Interpreter' -import {buildEmptyParserWithCaching} from './parser/common' -import {adr} from './testUtils' -import {DependencyGraph} from '../../src/DependencyGraph' -import {ColumnSearchStrategy} from '../../src/Lookup/SearchStrategy' -import {Statistics} from '../../src/statistics' -import {ArithmeticHelper} from '../../src/interpreter/ArithmeticHelper' -import {NamedExpressions} from '../../src/NamedExpressions' -import {Serialization} from '../../src/Serialization' -import {DateTimeHelper} from '../../src/DateTimeHelper' - -describe('Matrix size check tests', () => { - const config = new Config() - const functionRegistry = new FunctionRegistry(config) - const arraySizePredictor = new ArraySizePredictor(config, functionRegistry) - - new Interpreter( - config, - undefined as unknown as DependencyGraph, - undefined as unknown as ColumnSearchStrategy, - undefined as unknown as Statistics, - undefined as unknown as ArithmeticHelper, - functionRegistry, - undefined as unknown as NamedExpressions, - undefined as unknown as Serialization, - arraySizePredictor, - undefined as unknown as DateTimeHelper - ) - - it('check', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=mmult(A1:B3,C1:E2)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(3, 3)) - }) - - it('even for wrong size, we need to estimate', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=mmult(A1:B3,C1:E3)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(3, 3)) - }) - - it('check recursive', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=mmult(mmult(A1:B3,C1:E2), A1:B3)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(2, 3)) - }) - - it('wrong size estimation', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=mmult(mmult(A1:B3,C1:E3), A1:B3)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(2, 3)) - }) - - it('check maxpool', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=maxpool(A1:I9,3)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(3, 3)) - }) - - it('check with noninteger args', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=maxpool(A1:I9,B3)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(9, 9)) - }) - - it('check transpose with cell reference', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=transpose(A2)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(1, 1)) - }) - - it('check scalar', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=1234', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(1, 1, false)) - }) - - it('check cell reference', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=A1', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(1, 1, true)) - }) - - it('check binary array arithmetic #1', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=A1:D3+A1:C4', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(ArraySize.error()) - }) - - it('check binary array arithmetic #2', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=ARRAYFORMULA(A1:D3+A1:C4)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(4, 4)) - }) - - it('check unary array arithmetic #1', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=-A1:B3', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(ArraySize.error()) - }) - - it('check unary array arithmetic #2', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=ARRAYFORMULA(-A1:B3)', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(2, 3)) - }) - - it('check matrix parsing #1', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('={1,2,3;4,5,6}', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(3, 2)) - }) - - it('check matrix parsing #2', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('={{1;2},{3;4}}', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(2, 2)) - }) - - it('check matrix parsing #3', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('={1,{2,3},4;{5;6},{7,8;9,10},{11;12};13,{14,15},16}', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(4, 4)) - }) -}) - -describe('Matrix size check tests, with different config', () => { - const config = new Config({useArrayArithmetic: true}) - const functionRegistry = new FunctionRegistry(config) - const arraySizePredictor = new ArraySizePredictor(config, functionRegistry) - - new Interpreter( - config, - undefined as unknown as DependencyGraph, - undefined as unknown as ColumnSearchStrategy, - undefined as unknown as Statistics, - undefined as unknown as ArithmeticHelper, - functionRegistry, - undefined as unknown as NamedExpressions, - undefined as unknown as Serialization, - arraySizePredictor, - undefined as unknown as DateTimeHelper - ) - - it('check binary array arithmetic', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=A1:D3+A1:C4', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(4, 4)) - }) - - it('check unary array arithmetic', () => { - const parser = buildEmptyParserWithCaching(config) - const ast = parser.parse('=-A1:B3', adr('A1')).ast - - const size = arraySizePredictor.checkArraySize(ast, adr('A1')) - expect(size).toEqual(new ArraySize(2, 3)) - }) -}) diff --git a/test/unit/matrix.spec.ts b/test/unit/matrix.spec.ts deleted file mode 100644 index 3946567652..0000000000 --- a/test/unit/matrix.spec.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { ArraySize } from '../../src/ArraySize' -import { ArrayValue, NotComputedArray } from '../../src/ArrayValue' -import { EmptyValue } from '../../src/interpreter/InterpreterValue' - -describe('Matrix', () => { - it('fill', () => { - const matrix = new ArrayValue([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - expect(matrix.raw()).toEqual([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) - }) - - it('fill - zero sized rows', () => { - expect(() => { - new ArrayValue([]) - }).toThrowError('Incorrect array size') - }) - - it('fill - zero sized columns', () => { - expect(() => { - new ArrayValue([[], [], []]) - }).toThrowError('Incorrect array size') - }) - - it('add rows', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - matrix.addRows(1, 3) - expect(matrix.raw()).toEqual([ - [1, 2, 3], - [EmptyValue, EmptyValue, EmptyValue], - [EmptyValue, EmptyValue, EmptyValue], - [EmptyValue, EmptyValue, EmptyValue], - [4, 5, 6], - [7, 8, 9], - ]) - expect(matrix.height()).toEqual(6) - }) - - it('remove rows', () => { - const matrix = new ArrayValue([ - [1, 2], - [3, 4], - [5, 6], - [7, 8], - ]) - matrix.removeRows(1, 2) - expect(matrix.height()).toEqual(2) - expect(matrix.raw()).toEqual([ - [1, 2], - [7, 8], - ]) - }) - - it('remove rows out of bound', () => { - const matrix = new ArrayValue([ - [1, 2], - ]) - expect(() => { - matrix.removeRows(1, 1) - }).toThrowError('Array index out of bound') - }) - - it('add columns', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - matrix.addColumns(1, 2) - expect(matrix.width()).toEqual(5) - expect(matrix.raw()).toEqual([ - [1, EmptyValue, EmptyValue, 2, 3], - [4, EmptyValue, EmptyValue, 5, 6], - [7, EmptyValue, EmptyValue, 8, 9], - ]) - }) - - it('remove columns', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - matrix.removeColumns(1, 2) - expect(matrix.width()).toEqual(1) - expect(matrix.raw()).toEqual([ - [1], - [4], - [7], - ]) - }) - - it('remove columns - out of bounds', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - expect(() => { - matrix.removeColumns(3, 2) - }).toThrowError('Array index out of bound') - }) - - it('resize dimensions - increase height', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - const newSize = new ArraySize(3, 5) - matrix.resize(newSize) - expect(matrix.height()).toEqual(5) - expect(matrix.raw()).toEqual([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - [EmptyValue, EmptyValue, EmptyValue], - [EmptyValue, EmptyValue, EmptyValue], - ]) - }) - - it('resize dimensions - reduce height', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - expect(() => { - const newSize = new ArraySize(3, 1) - matrix.resize(newSize) - }).toThrowError('Resizing to smaller array') - }) - - it('resize dimensions - increase width', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - const newSize = new ArraySize(5, 3) - matrix.resize(newSize) - expect(matrix.width()).toEqual(5) - expect(matrix.raw()).toEqual([ - [1, 2, 3, EmptyValue, EmptyValue], - [4, 5, 6, EmptyValue, EmptyValue], - [7, 8, 9, EmptyValue, EmptyValue], - ]) - }) - - it('resize dimensions - reduce width', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - expect(() => { - const newSize = new ArraySize(1, 3) - matrix.resize(newSize) - }).toThrowError('Resizing to smaller array') - }) - - it('resize dimensions - increase height and width', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - const newSize = new ArraySize(5, 5) - matrix.resize(newSize) - expect(matrix.width()).toEqual(5) - expect(matrix.height()).toEqual(5) - expect(matrix.raw()).toEqual([ - [1, 2, 3, EmptyValue, EmptyValue], - [4, 5, 6, EmptyValue, EmptyValue], - [7, 8, 9, EmptyValue, EmptyValue], - [EmptyValue, EmptyValue, EmptyValue, EmptyValue, EmptyValue], - [EmptyValue, EmptyValue, EmptyValue, EmptyValue, EmptyValue], - ]) - }) - - it('get value', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - expect(matrix.get(0, 0)).toEqual(1) - expect(matrix.get(1, 0)).toEqual(2) - expect(matrix.get(2, 0)).toEqual(3) - expect(matrix.get(0, 1)).toEqual(4) - expect(matrix.get(1, 1)).toEqual(5) - expect(matrix.get(2, 1)).toEqual(6) - expect(matrix.get(0, 2)).toEqual(7) - expect(matrix.get(1, 2)).toEqual(8) - expect(matrix.get(2, 2)).toEqual(9) - }) - - it('get value - out of bounds', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - expect(() => { - matrix.get(3, 0) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.get(0, 3) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.get(3, 3) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.get(-1, 0) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.get(0, -1) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.get(-1, -1) - }).toThrowError('Array index out of bound') - }) - - it('set value', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - matrix.set(0, 0, 11) - matrix.set(1, 0, 12) - matrix.set(2, 0, 13) - matrix.set(0, 1, 14) - matrix.set(1, 1, 15) - matrix.set(2, 1, 16) - matrix.set(0, 2, 17) - matrix.set(1, 2, 18) - matrix.set(2, 2, 19) - expect(matrix.raw()).toEqual([ - [11, 12, 13], - [14, 15, 16], - [17, 18, 19], - ]) - }) - - it('set value - out of bounds', () => { - const matrix = new ArrayValue([ - [1, 2, 3], - [4, 5, 6], - [7, 8, 9], - ]) - expect(() => { - matrix.set(3, 0, 99) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.set(0, 3, 99) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.set(3, 3, 99) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.set(-1, 0, 99) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.set(0, -1, 99) - }).toThrowError('Array index out of bound') - expect(() => { - matrix.set(-1, -1, 99) - }).toThrowError('Array index out of bound') - }) -}) - -describe('NotComputedArray', () => { - it('width', () => { - const ncArraySize = new ArraySize(3, 2) - const ncArray = new NotComputedArray(ncArraySize) - expect(ncArray.width()).toEqual(3) - }) - - it('height', () => { - const ncArraySize = new ArraySize(3, 2) - const ncArray = new NotComputedArray(ncArraySize) - expect(ncArray.height()).toEqual(2) - }) - - it('get', () => { - const ncArraySize = new ArraySize(3, 2) - const ncArray = new NotComputedArray(ncArraySize) - expect(() => { - ncArray.get(0, 0) - }).toThrowError('Array not computed yet.') - }) - - it('simpleRangeValue', () => { - const ncArraySize = new ArraySize(3, 2) - const ncArray = new NotComputedArray(ncArraySize) - expect(() => { - ncArray.simpleRangeValue() - }).toThrowError('Array not computed yet.') - }) -}) diff --git a/test/unit/named-expressions.spec.ts b/test/unit/named-expressions.spec.ts deleted file mode 100644 index 774a8a372c..0000000000 --- a/test/unit/named-expressions.spec.ts +++ /dev/null @@ -1,2176 +0,0 @@ -import { - ExpectedValueOfTypeError, - ExportedCellChange, - ExportedNamedExpressionChange, - HyperFormula, - NamedExpressionDoesNotExistError, - NoSheetWithIdError, NotAFormulaError -} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {ErrorType} from '../../src' -import {Vertex} from '../../src/DependencyGraph' -import {ErrorMessage} from '../../src/error-message' -import {NoRelativeAddressesAllowedError} from '../../src' -import {adr, detailedError, expectArrayWithSameContent} from './testUtils' -import {Config} from '../../src/Config' -import {DependencyGraph} from '../../src/DependencyGraph' -import {Statistics} from '../../src/statistics' -import {FunctionRegistry} from '../../src/interpreter/FunctionRegistry' -import {LazilyTransformingAstService} from '../../src/LazilyTransformingAstService' -import {NamedExpressions} from '../../src/NamedExpressions' -import {Operations} from '../../src/Operations' -import {buildColumnSearchStrategy} from '../../src/Lookup/SearchStrategy' -import {CellContentParser} from '../../src/CellContentParser' -import {DateTimeHelper} from '../../src/DateTimeHelper' -import {NumberLiteralHelper} from '../../src/NumberLiteralHelper' -import {ParserWithCaching} from '../../src/parser' -import {ArraySizePredictor} from '../../src/ArraySize' - -describe('Named expressions - checking if its possible', () => { - it('should be possible to add named expression', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToAddNamedExpression('foo', '1')).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('foo', 'foo')).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('foo', null)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('foo', '=Sheet1!$A$1')).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('foo', '=Sheet1!$A$1', 0)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('_A', 1)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('A', 1)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('Aa', 1)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('B.', 1)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('foo_bar', 1)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('A...', 1)).toBe(true) - expect(engine.isItPossibleToAddNamedExpression('B___', 1)).toBe(true) - }) - - it('no if expression name invalid', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToAddNamedExpression('A1', 'foo')).toBe(false) - }) - - it('no if scope does not exists', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToAddNamedExpression('foo', '=A1', 1)).toBe(false) - }) - - it('no if trying to add formula with relative references', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToAddNamedExpression('foo', '=A1')).toBe(false) - expect(engine.isItPossibleToAddNamedExpression('foo', '=A$1')).toBe(false) - expect(engine.isItPossibleToAddNamedExpression('foo', '=$A1')).toBe(false) - expect(engine.isItPossibleToAddNamedExpression('foo', '=Sheet1!A1:A2')).toBe(false) - }) - - it('should be possible to remove named expression', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('foo', 'foo') - engine.addNamedExpression('bar', 'bar', 0) - expect(engine.isItPossibleToRemoveNamedExpression('foo')).toBe(true) - expect(engine.isItPossibleToRemoveNamedExpression('bar', 0)).toBe(true) - }) - - it('no if trying to remove not existing expression', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToRemoveNamedExpression('foo')).toBe(false) - }) - - it('no if trying to remove named expression from not existing scope', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToRemoveNamedExpression('foo', 1)).toBe(false) - }) - - it('should be possible to change named expression', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('foo', 'foo') - engine.addNamedExpression('bar', 'bar', 0) - expect(engine.isItPossibleToChangeNamedExpression('foo', 'bar')).toBe(true) - expect(engine.isItPossibleToChangeNamedExpression('bar', 'baz', 0)).toBe(true) - }) - - it('no if trying to change to formula with relative references', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('foo', 'foo') - expect(engine.isItPossibleToChangeNamedExpression('foo', '=A1')).toBe(false) - expect(engine.isItPossibleToChangeNamedExpression('foo', '=A$1')).toBe(false) - expect(engine.isItPossibleToChangeNamedExpression('foo', '=$A1')).toBe(false) - expect(engine.isItPossibleToChangeNamedExpression('foo', '=Sheet1!A1:A2')).toBe(false) - }) - - it('no if trying to change named expression in not existing scope', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToChangeNamedExpression('foo', '=A1', 1)).toBe(false) - }) - - it('no if trying to change not existing expression', () => { - const engine = HyperFormula.buildFromArray([]) - expect(engine.isItPossibleToChangeNamedExpression('foo', 'foo')).toBe(false) - }) -}) - -describe('Named expressions - name validity', () => { - describe('when created with addNamedExpression', () => { - it('name made of letters works', () => { - const name = 'ABC' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that starts with a valid cell reference works', () => { - const name = 'A9IOP' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that contains a valid cell reference works', () => { - const name = '___C42___' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that ends with a valid cell reference works', () => { - const name = '___C42' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that contains an underscore works', () => { - const name = 'HF2_2' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that contains a dot character works', () => { - const name = 'EXPR.2' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name starts with an underscore works', () => { - const name = '___' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name consisting of a underscore nad many dots works', () => { - const name = '_.......' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name with unicode characters works', () => { - const name = 'ąęļćłó' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('a one-character name works', () => { - const name = 'A' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('a 1000-character name works', () => { - const name = 'A'.repeat(1000) - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).not.toThrowError() - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that starts with a digit does not work', () => { - const name = '1definitelyIncorrectName' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqualError(detailedError(ErrorType.ERROR, 'Parsing error.')) - }) - - it('name that starts with a dot character does not work', () => { - const name = '.EXPR' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqualError(detailedError(ErrorType.ERROR, 'Parsing error.')) - }) - - it('name that contains a single quote character does not work', () => { - const name = "NAMED'EXPR" - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqualError(detailedError(ErrorType.ERROR, 'Parsing error.')) - }) - - it('name that contains an exclamation mark does not work', () => { - const name = 'NAMED!EXPR' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqualError(detailedError(ErrorType.ERROR, 'Parsing error.')) - }) - - it('name that is a valid cell reference does not work', () => { - const name = 'D42' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqual(null) // not error bc it is treated as a regular cell ref - }) - - it('name that is a valid cell reference with 4-letter column address does not work', () => { - const name = 'ABCD42' - const engine = HyperFormula.buildFromArray([[`=${name}`]], { maxColumns: 500000 }) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqual(null) // not error bc it is treated as a regular cell ref - }) - - it('name that is a valid R1C1-style reference does not work', () => { - const name = 'R5C17' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqualError(detailedError(ErrorType.ERROR, 'Parsing error.')) - }) - - it('name that is a R1C1-style reference with empty row number does not work', () => { - const name = 'RC17' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqual(null) // not error bc it is treated as a regular cell ref - }) - - it('name that is a R1C1-style reference with empty column number does not work', () => { - const name = 'R5C' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqualError(detailedError(ErrorType.ERROR, 'Parsing error.')) - }) - - it('name that is a R1C1-style reference with empty row and column numbers does not work', () => { - const name = 'RC' - const engine = HyperFormula.buildFromArray([[`=${name}`]]) - - expect(() => engine.addNamedExpression(name, '=42')).toThrowError(/Name .* is invalid/) - expect(engine.getCellValue(adr('A1', 0))).toEqualError(detailedError(ErrorType.ERROR, 'Parsing error.')) - }) - - it('validates characters which are allowed in name', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => engine.addNamedExpression('1CantStartWithNumber', '=42')).toThrowError(/Name .* is invalid/) - expect(() => engine.addNamedExpression('Spaces Are Not Allowed', '=42')).toThrowError(/Name .* is invalid/) - expect(() => engine.addNamedExpression('.CantStartWithDot', '=42')).toThrowError(/Name .* is invalid/) - expect(() => engine.addNamedExpression('_CanStartWithUnderscore', '=42')).not.toThrowError() - expect(() => engine.addNamedExpression('dots.are.fine', '=42')).not.toThrowError() - expect(() => engine.addNamedExpression('underscores_are_fine', '=42')).not.toThrowError() - expect(() => engine.addNamedExpression('ś.zażółć.gęślą.jaźń.unicode.is.fine', '=42')).not.toThrowError() - expect(() => engine.addNamedExpression('If.It.Only.Has.Something.Like.Reference.Not.In.Beginning.Then.Its.Ok.A100', '=42')).not.toThrowError() - expect(() => engine.addNamedExpression('A100.Reference_Like_Substrings_In_The_Beginning_Are_Also_Fine', '=42')).not.toThrowError() - expect(() => engine.addNamedExpression('A100', '=42')).toThrowError(/Name .* is invalid/) - expect(() => engine.addNamedExpression('$A$50', '=42')).toThrowError(/Name .* is invalid/) - expect(() => engine.addNamedExpression('SheetName!$A$50', '=42')).toThrowError(/Name .* is invalid/) - }) - }) - - describe('when created on initialization', () => { - it('name made of letters works', () => { - const name = 'ABC' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that starts with a valid cell reference works', () => { - const name = 'A9IOP' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that contains a valid cell reference works', () => { - const name = '___C42___' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that ends with a valid cell reference works', () => { - const name = '___C42' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that contains an underscore works', () => { - const name = 'HF2_2' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that contains a dot character works', () => { - const name = 'EXPR.2' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name starts with an underscore works', () => { - const name = '___' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name consisting of a underscore nad many dots works', () => { - const name = '_.......' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name with unicode characters works', () => { - const name = 'ąęļćłó' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('a one-character name works', () => { - const name = 'A' - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('a 1000-character name works', () => { - const name = 'A'.repeat(1000) - const engine = HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }]) - - expect(engine.getCellValue(adr('A1', 0))).toEqual(42) - }) - - it('name that starts with a digit does not work', () => { - const name = '1definitelyIncorrectName' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that starts with a dot character does not work', () => { - const name = '.EXPR' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that contains a single quote character does not work', () => { - const name = "NAMED'EXPR" - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that contains an exclamation mark does not work', () => { - const name = 'NAMED!EXPR' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that is a valid cell reference does not work', () => { - const name = 'D42' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that is a valid cell reference with 4-letter column address does not work', () => { - const name = 'ABCD42' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], { maxColumns: 500000 }, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that is a valid R1C1-style reference does not work', () => { - const name = 'R5C17' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that is a R1C1-style reference with empty row number does not work', () => { - const name = 'RC17' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that is a R1C1-style reference with empty column number does not work', () => { - const name = 'R5C' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('name that is a R1C1-style reference with empty row and column numbers does not work', () => { - const name = 'RC' - - expect(() => HyperFormula.buildFromArray([[`=${name}`]], {}, [{ name, expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - - it('validates characters which are allowed in name', () => { - expect(() => HyperFormula.buildEmpty({}, [{ name: '1CantStartWithNumber', expression: '=42' }])).toThrowError(/Name .* is invalid/) - expect(() => HyperFormula.buildEmpty({}, [{ name: 'Spaces Are Not Allowed', expression: '=42' }])).toThrowError(/Name .* is invalid/) - expect(() => HyperFormula.buildEmpty({}, [{ name: '.CantStartWithDot', expression: '=42' }])).toThrowError(/Name .* is invalid/) - expect(() => HyperFormula.buildEmpty({}, [{ name: '_CanStartWithUnderscore', expression: '=42' }])).not.toThrowError() - expect(() => HyperFormula.buildEmpty({}, [{ name: 'dots.are.fine', expression: '=42' }])).not.toThrowError() - expect(() => HyperFormula.buildEmpty({}, [{ name: 'underscores_are_fine', expression: '=42' }])).not.toThrowError() - expect(() => HyperFormula.buildEmpty({}, [{ name: 'ś.zażółć.gęślą.jaźń.unicode.is.fine', expression: '=42' }])).not.toThrowError() - expect(() => HyperFormula.buildEmpty({}, [{ name: 'If.It.Only.Has.Something.Like.Reference.Not.In.Beginning.Then.Its.Ok.A100', expression: '=42' }])).not.toThrowError() - expect(() => HyperFormula.buildEmpty({}, [{ name: 'A100.Reference_Like_Substrings_In_The_Beginning_Are_Also_Fine', expression: '=42' }])).not.toThrowError() - expect(() => HyperFormula.buildEmpty({}, [{ name: 'A100', expression: '=42' }])).toThrowError(/Name .* is invalid/) - expect(() => HyperFormula.buildEmpty({}, [{ name: '$A$50', expression: '=42' }])).toThrowError(/Name .* is invalid/) - expect(() => HyperFormula.buildEmpty({}, [{ name: 'SheetName!$A$50', expression: '=42' }])).toThrowError(/Name .* is invalid/) - }) - }) -}) - -describe('Named expressions - absolute references only', () => { - describe('when created with addNamedExpression', () => { - it('adding named expression allows only for absolute addresses', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(() => { - engine.addNamedExpression('foo', '=A1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.addNamedExpression('foo', '=Sheet1!A1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.addNamedExpression('foo', '=$A$1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.addNamedExpression('foo', '=Sheet1!$A1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.addNamedExpression('foo', '=Sheet1!A$1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.addNamedExpression('foo', '=Sheet1!A1:A2') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.addNamedExpression('foo', '=Sheet1!A:B') - }).toThrow(new NoRelativeAddressesAllowedError()) - }) - - it('changing named expression allows only for absolute addresses', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.addNamedExpression('foo', 'foo') - - expect(() => { - engine.changeNamedExpression('foo', '=A1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.changeNamedExpression('foo', '=Sheet1!A1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.changeNamedExpression('foo', '=$A$1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.changeNamedExpression('foo', '=Sheet1!$A1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.changeNamedExpression('foo', '=Sheet1!A$1') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.changeNamedExpression('foo', '=Sheet1!A1:A2') - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - engine.changeNamedExpression('foo', '=Sheet1!A:B') - }).toThrow(new NoRelativeAddressesAllowedError()) - }) - }) - - describe('when created on initialization', () => { - it('creating named expression allows only for absolute addresses', () => { - expect(() => { - HyperFormula.buildFromArray([], {}, [{ name: 'foo', expression: '=A1' }]) - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - HyperFormula.buildFromArray([], {}, [{ name: 'foo', expression: '=Sheet1!A1' }]) - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - HyperFormula.buildFromArray([], {}, [{ name: 'foo', expression: '=$A$1' }]) - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - HyperFormula.buildFromArray([], {}, [{ name: 'foo', expression: '=Sheet1!$A1' }]) - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - HyperFormula.buildFromArray([], {}, [{ name: 'foo', expression: '=Sheet1!A$1' }]) - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - HyperFormula.buildFromArray([], {}, [{ name: 'foo', expression: '=Sheet1!A1:A2' }]) - }).toThrow(new NoRelativeAddressesAllowedError()) - expect(() => { - HyperFormula.buildFromArray([], {}, [{ name: 'foo', expression: '=Sheet1!A:B' }]) - }).toThrow(new NoRelativeAddressesAllowedError()) - }) - }) -}) - -describe('Named expressions - store manipulation', () => { - describe('when created with addNamedExpression', () => { - it('basic usage with global named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - - engine.addNamedExpression('myName', '=Sheet1!$A$1+10') - - expect(engine.getNamedExpressionValue('myName')).toEqual(52) - }) - - it('using string expression', () => { - const engine = HyperFormula.buildEmpty() - - const changes = engine.addNamedExpression('myName', 'foobarbaz') - - expect(changes).toEqual([new ExportedNamedExpressionChange('myName', 'foobarbaz')]) - expect(engine.getNamedExpressionValue('myName')).toEqual('foobarbaz') - }) - - it('using number expression', () => { - const engine = HyperFormula.buildEmpty() - - const changes = engine.addNamedExpression('myName', '42') - - expect(changes).toEqual([new ExportedNamedExpressionChange('myName', 42)]) - expect(engine.getNamedExpressionValue('myName')).toEqual(42) - }) - - it('using empty expression', () => { - const engine = HyperFormula.buildEmpty() - - const changes = engine.addNamedExpression('myName', null) - - expect(changes).toEqual([new ExportedNamedExpressionChange('myName', null)]) - expect(engine.getNamedExpressionValue('myName')).toBe(null) - }) - - it('using native number as expression', () => { - const engine = HyperFormula.buildEmpty() - - const changes = engine.addNamedExpression('myName', 42) - - expect(changes).toEqual([new ExportedNamedExpressionChange('myName', 42)]) - expect(engine.getNamedExpressionValue('myName')).toEqual(42) - }) - - it('using native boolean as expression', () => { - const engine = HyperFormula.buildEmpty() - - const changes = engine.addNamedExpression('myName', true) - - expect(changes).toEqual([new ExportedNamedExpressionChange('myName', true)]) - expect(engine.getNamedExpressionValue('myName')).toEqual(true) - }) - - it('using error expression', () => { - const engine = HyperFormula.buildEmpty() - - const changes = engine.addNamedExpression('myName', '#VALUE!') - - expect(changes).toEqual([new ExportedNamedExpressionChange('myName', detailedError(ErrorType.VALUE))]) - expect(engine.getNamedExpressionValue('myName')).toEqualError(detailedError(ErrorType.VALUE)) - }) - - it('works for more formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - - engine.addNamedExpression('myName.1', '=Sheet1!$A$1+10') - engine.addNamedExpression('myName.2', '=Sheet1!$A$1+11') - - expect(engine.getNamedExpressionValue('myName.1')).toEqual(52) - expect(engine.getNamedExpressionValue('myName.2')).toEqual(53) - }) - - it('adding the same named expression twice on global level is forbidden', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('myName', '=Sheet1!$A$1+10') - - expect(() => { - engine.addNamedExpression('myName', '=Sheet1!A1+10') - }).toThrowError('Name of Named Expression \'myName\' is already present') - }) - - it('adding the same named expression twice on local level is forbidden', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('myName', '=Sheet1!$A$1+10', 0) - - expect(() => { - engine.addNamedExpression('myName', '=Sheet1!A1+10', 0) - }).toThrowError('Name of Named Expression \'myName\' is already present') - }) - - it('when adding named expression, matrix formulas are not accepted', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => { - engine.addNamedExpression('myName', '=TRANSPOSE(A1:B2)') - }).toThrowError(/Relative addresses not allowed in named expressions./) - }) - - it('retrieving non-existing named expression', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.getNamedExpressionValue('nonExistentNameExpression')).toBe(undefined) - expect(engine.getNamedExpressionFormula('nonExistentNameExpression')).toBe(undefined) - }) - - it('removing named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - engine.addNamedExpression('myName', '=Sheet1!$A$1') - - engine.removeNamedExpression('myName') - - expect(engine.getNamedExpressionValue('myName')).toBe(undefined) - expect(engine.setCellContents(adr('A1'), '43').length).toBe(1) - }) - - it('removing local named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - engine.addNamedExpression('myName', '13') - engine.addNamedExpression('myName', '=Sheet1!$A$1', 0) - - engine.removeNamedExpression('myName', 0) - - expect(engine.getNamedExpressionValue('myName', 0)).toBe(undefined) - expect(engine.getNamedExpressionValue('myName')).toBe(13) - }) - - it('is possible to change named expression formula to other', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - engine.addNamedExpression('myName', '=Sheet1!$A$1+10') - - engine.changeNamedExpression('myName', '=Sheet1!$A$1+11') - - expect(engine.getNamedExpressionValue('myName')).toEqual(53) - }) - - it('is possible to change named expression formula to other expression', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - engine.addNamedExpression('myName', '=Sheet1!$A$1+10') - - engine.changeNamedExpression('myName', 58) - - expect(engine.getNamedExpressionValue('myName')).toEqual(58) - }) - - it('is possible to change named expression formula on local level', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - engine.addNamedExpression('myName', '=100', 0) - - engine.changeNamedExpression('myName', '=200', 0) - - expect(engine.getNamedExpressionValue('myName', 0)).toEqual(200) - }) - - it('when changing named expression, matrices are not supported', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('myName', '=42') - - expect(() => { - engine.changeNamedExpression('myName', '=TRANSPOSE(A1:B2)') - }).toThrowError(/Relative addresses not allowed in named expressions./) - }) - - it('changing not existing named expression', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => { - engine.changeNamedExpression('myName', '=42') - }).toThrowError('Named Expression \'myName\' does not exist') - }) - - it('changing named expression from non existing sheet', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => { - engine.changeNamedExpression('myName', '=42', 1) - }).toThrowError(NoSheetWithIdError) - }) - - it('listing named expressions', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('myName.1', '=42') - engine.addNamedExpression('myName.2', '=42') - - const namedExpressions = engine.listNamedExpressions() - - expect(namedExpressions).toEqual([ - 'myName.1', - 'myName.2', - ]) - }) - - it('listing scoped named expressions', () => { - const engine = HyperFormula.buildFromSheets({sheet1: [], sheet2: []}) - engine.addNamedExpression('myName.1', '=42', 0) - engine.addNamedExpression('myName.2', '=42', 1) - - const namedExpressions = engine.listNamedExpressions(1) - - expect(namedExpressions).toEqual([ - 'myName.2', - ]) - }) - - it('adding named expressions is case insensitive', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('myName', '=42') - - expect(engine.getNamedExpressionValue('MYname')).toEqual(42) - expect(() => { - engine.changeNamedExpression('MYname', '=43') - }).not.toThrowError() - expect(() => { - engine.removeNamedExpression('MYname') - }).not.toThrowError() - }) - - it('allow even 255 character named expressions', () => { - const engine = HyperFormula.buildEmpty() - - const longExpressionName = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - - expect(longExpressionName.length).toBe(255) - expect(() => { - engine.addNamedExpression(longExpressionName, '=42') - }).not.toThrowError() - }) - - it('#getNamedExpressionFormula when it exists', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.addNamedExpression('myName.1', '=Sheet1!$A$1+10') - - expect(engine.getNamedExpressionFormula('myName.1')).toEqual('=Sheet1!$A$1+10') - }) - - it('#getNamedExpressionFormula when there is no such named expression', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.getNamedExpressionFormula('not.existing')).toBeUndefined() - }) - - it('#getNamedExpressionFormula when named expression is not formula', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.addNamedExpression('myName.1', '42') - - expect(engine.getNamedExpressionFormula('myName.1')).toBeUndefined() - }) - - it('#getNamedExpressionFormula when there is no such sheet', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(() => { - engine.getNamedExpressionFormula('myName.1', 1) - }).toThrowError(NoSheetWithIdError) - }) - - it('local level named expressions have separate storages', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - - engine.addNamedExpression('myName', '=42') - engine.addNamedExpression('myName', '=13', 0) - - expect(engine.getNamedExpressionValue('myName')).toEqual(42) - expect(engine.getNamedExpressionValue('myName', 0)).toEqual(13) - expect(engine.getNamedExpressionFormula('myName')).toEqual('=42') - expect(engine.getNamedExpressionFormula('myName', 0)).toEqual('=13') - }) - - it('when trying to add named expression to nonexisting sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - - expect(() => { - engine.addNamedExpression('myName', '=13', 1) - }).toThrowError(NoSheetWithIdError) - }) - }) - - describe('when created on initialization', () => { - it('basic usage with global named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ], {}, [{ name: 'myName', expression: '=Sheet1!$A$1+10' }]) - - expect(engine.getNamedExpressionValue('myName')).toEqual(52) - }) - - it('using string expression', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'myName', expression: 'foobarbaz' }]) - - expect(engine.getNamedExpressionValue('myName')).toEqual('foobarbaz') - }) - - it('using number expression', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'myName', expression: '42' }]) - - expect(engine.getNamedExpressionValue('myName')).toEqual(42) - }) - - it('using empty expression', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'myName', expression: null }]) - - expect(engine.getNamedExpressionValue('myName')).toBe(null) - }) - - it('using native number as expression', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'myName', expression: 42 }]) - - expect(engine.getNamedExpressionValue('myName')).toEqual(42) - }) - - it('using native boolean as expression', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'myName', expression: true }]) - - expect(engine.getNamedExpressionValue('myName')).toEqual(true) - }) - - it('using error expression', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'myName', expression: '#VALUE!' }]) - - expect(engine.getNamedExpressionValue('myName')).toEqualError(detailedError(ErrorType.VALUE)) - }) - - it('works for more formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ], {}, [ - { name: 'myName.1', expression: '=Sheet1!$A$1+10' }, - { name: 'myName.2', expression: '=Sheet1!$A$1+11' } - ]) - - expect(engine.getNamedExpressionValue('myName.1')).toEqual(52) - expect(engine.getNamedExpressionValue('myName.2')).toEqual(53) - }) - - it('adding the same named expression twice on global level is forbidden', () => { - expect(() => { - HyperFormula.buildFromArray([], {}, [ - { name: 'myName', expression: '=Sheet1!$A$1+10' }, - { name: 'myName', expression: '=Sheet1!$A$1+11' } - ]) - }).toThrowError('Name of Named Expression \'myName\' is already present') - }) - - it('adding the same named expression twice on local level is forbidden', () => { - expect(() => { - HyperFormula.buildFromArray([], {}, [ - { name: 'myName', expression: '=Sheet1!$A$1+10', scope: 0 }, - { name: 'myName', expression: '=Sheet1!$A$1+11', scope: 0 } - ]) - }).toThrowError('Name of Named Expression \'myName\' is already present') - }) - - it('when creating named expression, matrix formulas are not accepted', () => { - expect(() => { - HyperFormula.buildEmpty({}, [{ name: 'myName', expression: '=TRANSPOSE(A1:B2)' }]) - }).toThrowError(/Relative addresses not allowed in named expressions./) - }) - - it('retrieving non-existing named expression', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.getNamedExpressionValue('nonExistentNameExpression')).toBe(undefined) - expect(engine.getNamedExpressionFormula('nonExistentNameExpression')).toBe(undefined) - }) - - it('listing named expressions', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'myName.1', expression: '=42' }, - { name: 'myName.2', expression: '=42' } - ]) - - const namedExpressions = engine.listNamedExpressions() - - expect(namedExpressions).toEqual([ - 'myName.1', - 'myName.2', - ]) - }) - - it('listing scoped named expressions', () => { - const engine = HyperFormula.buildFromSheets({sheet1: [], sheet2: []}, {}, [ - { name: 'myName.1', expression: '=42', scope: 0 }, - { name: 'myName.2', expression: '=42', scope: 1 } - ]) - - const namedExpressions = engine.listNamedExpressions(1) - - expect(namedExpressions).toEqual([ - 'myName.2', - ]) - }) - - it('named expressions are case insensitive', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'myName', expression: '=42' }]) - - expect(engine.getNamedExpressionValue('MYname')).toEqual(42) - }) - - it('allow even 255 character named expressions', () => { - const longExpressionName = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' - - expect(longExpressionName.length).toBe(255) - expect(() => { - HyperFormula.buildEmpty({}, [{ name: longExpressionName, expression: '=42' }]) - }).not.toThrowError() - }) - - it('#getNamedExpressionFormula when it exists', () => { - const engine = HyperFormula.buildFromArray([], {}, [{ name: 'myName.1', expression: '=Sheet1!$A$1+10' }]) - - expect(engine.getNamedExpressionFormula('myName.1')).toEqual('=Sheet1!$A$1+10') - }) - - it('#getNamedExpressionFormula when there is no such named expression', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.getNamedExpressionFormula('not.existing')).toBeUndefined() - }) - - it('#getNamedExpressionFormula when named expression is not formula', () => { - const engine = HyperFormula.buildFromArray([], {}, [{ name: 'myName.1', expression: '42' }]) - - expect(engine.getNamedExpressionFormula('myName.1')).toBeUndefined() - }) - - it('#getNamedExpressionFormula when there is no such sheet', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(() => { - engine.getNamedExpressionFormula('myName.1', 1) - }).toThrowError(NoSheetWithIdError) - }) - - it('local level named expressions have separate storages', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ], {}, [ - { name: 'myName', expression: '=42' }, - { name: 'myName', expression: '=13', scope: 0 } - ]) - - expect(engine.getNamedExpressionValue('myName')).toEqual(42) - expect(engine.getNamedExpressionValue('myName', 0)).toEqual(13) - expect(engine.getNamedExpressionFormula('myName')).toEqual('=42') - expect(engine.getNamedExpressionFormula('myName', 0)).toEqual('=13') - }) - - it('when trying to create named expression with nonexisting sheet scope', () => { - expect(() => { - HyperFormula.buildFromArray([ - ['42'], - ], {}, [{ name: 'myName', expression: '=13', scope: 1 }]) - }).toThrowError(NoSheetWithIdError) - }) - }) -}) - -/** - * A mock object for testing the dependency graph for the existence of the named expression vertex. - */ -const namedExpressionVertex = (engine: HyperFormula, expressionName: string, sheetId?: number): Vertex => { - let namedExpression - if (sheetId === undefined) { - namedExpression = engine.dependencyGraph.namedExpressions.workbookNamedExpressionOrPlaceholder(expressionName)! - } else { - namedExpression = engine.dependencyGraph.namedExpressions.namedExpressionForScope(expressionName, sheetId)! - } - return engine.dependencyGraph.fetchCell(namedExpression.address) -} - - describe('Named expressions - adding', () => { - describe('when created with addNamedExpression', () => { - it('doesn\'t throw when added named expression is used in a formula twice', () => { - const engine = HyperFormula.buildFromArray([ - ['55', '=age + age'] - ]) - - engine.addNamedExpression('age', '=Sheet1!$A$1', 0) - - expect(engine.getCellValue(adr('B1'))).toEqual(110) - }) - }) - - describe('when created on initialization', () => { - it('doesn\'t throw when named expression is used in a formula twice', () => { - const engine = HyperFormula.buildFromArray([ - ['55', '=age + age'] - ], {}, [{ name: 'age', expression: '=Sheet1!$A$1', scope: 0 }]) - - expect(engine.getCellValue(adr('B1'))).toEqual(110) - }) - }) - }) - -describe('Named expressions - evaluation', () => { - describe('when created with addNamedExpression', () => { - it('is recomputed', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - engine.addNamedExpression('myName', '=Sheet1!$A$1+10') - - const changes = engine.setCellContents(adr('A1'), '20') - - expect(changes.length).toBe(2) - expect(changes).toContainEqual(new ExportedNamedExpressionChange('myName', 30)) - expect(engine.getNamedExpressionValue('myName')).toEqual(30) - }) - - it('is recomputed on every change', () => { - const hfInstance = HyperFormula.buildFromSheets( - { Sheet1: [[1]] }, - {} - ) - - hfInstance.addNamedExpression('test', '=Sheet1!$A$1') - - expect(hfInstance.getNamedExpressionValue('test')).toEqual(1) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 2) - expect(hfInstance.getNamedExpressionValue('test')).toEqual(2) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 3) - expect(hfInstance.getNamedExpressionValue('test')).toEqual(3) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 4) - expect(hfInstance.getNamedExpressionValue('test')).toEqual(4) - }) - - it('is recomputed on every change (array formula)', () => { - const options = { - licenseKey: 'gpl-v3', - evaluateNullToZero: true, - } - - const hfInstance = HyperFormula.buildFromSheets( - { - Sheet1: [[1, 2, '=SUM(test)']], - }, - options - ) - - hfInstance.addNamedExpression('test', '=Sheet1!$A$1:$B$1') - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 4) - expect(hfInstance.getCellValue(adr('C1'))).toEqual(6) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 14) - expect(hfInstance.getCellValue(adr('C1'))).toEqual(16) - }) - - it('should reevaluate volatile function in named expression', () => { - const engine = HyperFormula.buildFromArray([]) - - engine.addNamedExpression('volatileExpression', '=RAND()') - const valueBeforeRecomputation = engine.getNamedExpressionValue('volatileExpression') - - const changes = engine.setCellContents(adr('A1'), 'foo') - - const valueAfterRecomputation = engine.getNamedExpressionValue('volatileExpression') - expect(valueAfterRecomputation).not.toEqual(valueBeforeRecomputation) - expect(changes).toContainEqual(new ExportedCellChange(adr('A1'), 'foo')) - expect(changes).toContainEqual(new ExportedNamedExpressionChange('volatileExpression', valueAfterRecomputation!)) - }) - - it('adds edge to dependency', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('FOO', '=42') - - engine.setCellContents(adr('A1'), '=FOO+10') - - const fooVertex = engine.dependencyGraph.fetchNamedExpressionVertex('FOO', 0).vertex - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(fooVertex, a1)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toEqual(52) - }) - - it('named expression dependency works if named expression was defined later', () => { - const engine = HyperFormula.buildFromArray([ - ['=FOO'] - ]) - - engine.addNamedExpression('FOO', '=42') - - const fooVertex = engine.dependencyGraph.fetchNamedExpressionVertex('FOO', 0).vertex - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(fooVertex, a1)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toEqual(42) - }) - - it('removed named expression returns NAME error', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('FOO', '=42') - engine.setCellContents(adr('A1'), '=FOO+10') - - engine.removeNamedExpression('FOO') - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('FOO'))) - }) - - it('removing node dependent on named expression', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('FOO', '=42') - engine.setCellContents(adr('A1'), '=FOO+10') - - engine.setCellContents(adr('A1'), null) - - const fooVertex = engine.dependencyGraph.fetchNamedExpressionVertex('FOO', 0).vertex - expect(engine.graph.adjacentNodes(fooVertex).size).toBe(0) - }) - - it('named expression returns REF error after removing referenced sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['=42'] - ]) - engine.addNamedExpression('FOO', '=Sheet1!$A$1 + 10') - - engine.removeSheet(engine.getSheetId('Sheet1')!) - - expect(engine.getNamedExpressionFormula('FOO')).toEqual('=Sheet1!$A$1 + 10') - expect(engine.getNamedExpressionValue('FOO')).toEqualError(detailedError(ErrorType.REF)) - }) - - it('local named expression shadows global one', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('FOO', '=42') - engine.addNamedExpression('FOO', '=13', 0) - - engine.setCellContents(adr('A1'), '=FOO+10') - - const localFooVertex = engine.dependencyGraph.fetchNamedExpressionVertex('FOO', 0).vertex - const globalFooVertex = engine.dependencyGraph.fetchCell(engine.dependencyGraph.namedExpressions.namedExpressionForScope('FOO')!.address) - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(localFooVertex, a1)).toBe(true) - expect(engine.graph.existsEdge(globalFooVertex, a1)).toBe(false) - expect(engine.getCellValue(adr('A1'))).toEqual(23) - }) - - it('removing local named expression binds all the edges to global one', () => { - const engine = HyperFormula.buildFromArray([[]]) - engine.addNamedExpression('foo', '10') - engine.addNamedExpression('foo', '20', 0) - engine.setCellContents(adr('A1'), [['=foo']]) - const localFooVertex = namedExpressionVertex(engine, 'foo', 0) - const globalFooVertex = namedExpressionVertex(engine, 'foo') - - engine.removeNamedExpression('foo', 0) - - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(localFooVertex, a1)).toBe(false) - expect(engine.graph.existsEdge(globalFooVertex, a1)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toEqual(10) - }) - - it('removing local named expression binds all the edges to global one even if it doesnt exist', () => { - const engine = HyperFormula.buildFromArray([[]]) - engine.addNamedExpression('foo', '20', 0) - engine.setCellContents(adr('A1'), [['=foo']]) - const localFooVertex = namedExpressionVertex(engine, 'foo', 0) - - engine.removeNamedExpression('foo', 0) - - const globalFooVertex = namedExpressionVertex(engine, 'foo') - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(localFooVertex, a1)).toBe(false) - expect(engine.graph.existsEdge(globalFooVertex, a1)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('foo'))) - }) - - it('adding local named expression binds all the edges from global one', () => { - const engine = HyperFormula.buildFromArray([[]]) - engine.addNamedExpression('foo', '20') - engine.setCellContents(adr('A1'), [['=foo']]) - const globalFooVertex = namedExpressionVertex(engine, 'foo') - - engine.addNamedExpression('foo', '30', 0) - - const localFooVertex = namedExpressionVertex(engine, 'foo', 0) - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(localFooVertex, a1)).toBe(true) - expect(engine.graph.existsEdge(globalFooVertex, a1)).toBe(false) - expect(engine.getCellValue(adr('A1'))).toEqual(30) - }) - }) - - describe('when created on initialization', () => { - it('is recomputed on every change', () => { - const hfInstance = HyperFormula.buildFromSheets( - { Sheet1: [[1]] }, - {}, - [{ name: 'test', expression: '=Sheet1!$A$1' }] - ) - - expect(hfInstance.getNamedExpressionValue('test')).toEqual(1) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 2) - expect(hfInstance.getNamedExpressionValue('test')).toEqual(2) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 3) - expect(hfInstance.getNamedExpressionValue('test')).toEqual(3) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 4) - expect(hfInstance.getNamedExpressionValue('test')).toEqual(4) - }) - - it('is recomputed on every change (array formula)', () => { - const options = { - licenseKey: 'gpl-v3', - evaluateNullToZero: true, - } - - const hfInstance = HyperFormula.buildFromSheets( - { - Sheet1: [[1, 2, '=SUM(test)']], - }, - options, - [ - { - name: 'test', - expression: '=Sheet1!$A$1:$B$1', - }, - ] - ) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 4) - expect(hfInstance.getCellValue(adr('C1'))).toEqual(6) - - hfInstance.setCellContents({ sheet: 0, col: 0, row: 0 }, 14) - expect(hfInstance.getCellValue(adr('C1'))).toEqual(16) - }) - - it('is recomputed', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ], {}, [{ name: 'myName', expression: '=Sheet1!$A$1+10' }]) - - const changes = engine.setCellContents(adr('A1'), '20') - - expect(changes.length).toBe(2) - expect(changes).toContainEqual(new ExportedNamedExpressionChange('myName', 30)) - expect(engine.getNamedExpressionValue('myName')).toEqual(30) - }) - - it('should reevaluate volatile function in named expression', () => { - const engine = HyperFormula.buildFromArray([], {}, [{ name: 'volatileExpression', expression: '=RAND()' }]) - - const valueBeforeRecomputation = engine.getNamedExpressionValue('volatileExpression') - - const changes = engine.setCellContents(adr('A1'), 'foo') - - const valueAfterRecomputation = engine.getNamedExpressionValue('volatileExpression') - expect(valueAfterRecomputation).not.toEqual(valueBeforeRecomputation) - expect(changes).toContainEqual(new ExportedCellChange(adr('A1'), 'foo')) - expect(changes).toContainEqual(new ExportedNamedExpressionChange('volatileExpression', valueAfterRecomputation!)) - }) - - it('adds edge to dependency', () => { - const engine = HyperFormula.buildFromArray([ - ['=FOO+10'] - ], {}, [{ name: 'FOO', expression: '=42' }]) - - const fooVertex = engine.dependencyGraph.fetchNamedExpressionVertex('FOO', 0).vertex - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(fooVertex, a1)).toBe(true) - expect(engine.getCellValue(adr('A1'))).toEqual(52) - }) - - it('named expression returns REF error after removing referenced sheet', () => { - const engine = HyperFormula.buildFromArray([ - ['=42'] - ], {}, [{ name: 'FOO', expression: '=Sheet1!$A$1 + 10' }]) - - engine.removeSheet(0) - - expect(engine.getNamedExpressionFormula('FOO')).toEqual('=Sheet1!$A$1 + 10') - expect(engine.getNamedExpressionValue('FOO')).toEqualError(detailedError(ErrorType.REF)) - }) - - it('local named expression shadows global one', () => { - const engine = HyperFormula.buildFromArray([ - ['=FOO+10'] - ], {}, [ - { name: 'FOO', expression: '=42' }, - { name: 'FOO', expression: '=13', scope: 0 } - ]) - - const localFooVertex = engine.dependencyGraph.fetchNamedExpressionVertex('FOO', 0).vertex - const globalFooVertex = engine.dependencyGraph.fetchCell(engine.dependencyGraph.namedExpressions.namedExpressionForScope('FOO')!.address) - const a1 = engine.dependencyGraph.fetchCell(adr('A1')) - expect(engine.graph.existsEdge(localFooVertex, a1)).toBe(true) - expect(engine.graph.existsEdge(globalFooVertex, a1)).toBe(false) - expect(engine.getCellValue(adr('A1'))).toEqual(23) - }) - }) - - it('NAME error when there is no such named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['=FOO'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('FOO'))) - }) -}) - -describe('Named expressions - cross scope', () => { - describe('when created with addNamedExpression', () => { - it('should be possible to reference another sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet2!$A$1', 0) - - expect(engine.getNamedExpressionValue('expr', 0)).toEqual('bar') - }) - - it('should be possible to add named expressions with same name to two different scopes', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar', '=expr']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - engine.addNamedExpression('expr', '=Sheet2!$A$1', 1) - - expect(engine.getCellValue(adr('B1'))).toEqual('foo') - expect(engine.getCellValue(adr('B1', 1))).toEqual('bar') - }) - - it('should be possible to access named expression only from its scope', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar', '=expr']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - - expect(engine.getCellValue(adr('B1'))).toEqual('foo') - expect(engine.getCellValue(adr('B1', 1))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('expr'))) - }) - - it('should add named expression to global scope when moving formula to other sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1), adr('B1', 1)) - - expect(engine.getNamedExpressionFormula('expr', 0)).toEqual('=Sheet1!$A$1') - expect(engine.getNamedExpressionFormula('expr')).toEqual('=Sheet1!$A$1') - expect(engine.getCellValue(adr('B1', 0))).toBe(null) - expect(engine.getCellValue(adr('B1', 1))).toEqual('foo') - }) - - it('should add named expression to global scope when cut pasting formula to other sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - - engine.cut(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.paste(adr('B1', 1)) - - expect(engine.getNamedExpressionFormula('expr', 0)).toEqual('=Sheet1!$A$1') - expect(engine.getNamedExpressionFormula('expr')).toEqual('=Sheet1!$A$1') - expect(engine.getCellValue(adr('B1', 0))).toBe(null) - expect(engine.getCellValue(adr('B1', 1))).toEqual('foo') - }) - - it('should add named expression to global scope when copying formula to other sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.paste(adr('B1', 1)) - - expect(engine.getNamedExpressionFormula('expr', 0)).toEqual('=Sheet1!$A$1') - expect(engine.getNamedExpressionFormula('expr')).toEqual('=Sheet1!$A$1') - expect(engine.getCellValue(adr('B1', 0))).toEqual('foo') - expect(engine.getCellValue(adr('B1', 1))).toEqual('foo') - }) - - it('should add named expression to global scope even if cell was modified before pasting', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.setCellContents(adr('B1'), [['baz']]) - engine.paste(adr('B1', 1)) - - expect(engine.getNamedExpressionFormula('expr', 0)).toEqual('=Sheet1!$A$1') - expect(engine.getNamedExpressionFormula('expr')).toEqual('=Sheet1!$A$1') - expect(engine.getCellValue(adr('B1', 0))).toEqual('baz') - expect(engine.getCellValue(adr('B1', 1))).toEqual('foo') - }) - - it('should use already existing named expression in other sheet when moving formula', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - engine.addNamedExpression('expr', '=Sheet2!$A$1', 1) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1), adr('B1', 1)) - - expect(engine.getNamedExpressionFormula('expr')).toEqual(undefined) - expect(engine.getNamedExpressionFormula('expr', 0)).toEqual('=Sheet1!$A$1') - expect(engine.getNamedExpressionFormula('expr', 1)).toEqual('=Sheet2!$A$1') - expect(engine.getCellValue(adr('B1', 0))).toBe(null) - expect(engine.getCellValue(adr('B1', 1))).toEqual('bar') - // ensure edges are correct - const sourceScopeNEVertex = engine.dependencyGraph.fetchNamedExpressionVertex('expr', 0).vertex - const targetScopeNEVertex = engine.dependencyGraph.fetchNamedExpressionVertex('expr', 1).vertex - const targetFormulaVertex = engine.dependencyGraph.getCell(adr('B1', 1))! - expect(engine.dependencyGraph.existsEdge(sourceScopeNEVertex, targetFormulaVertex)).toBe(false) - expect(engine.dependencyGraph.existsEdge(targetScopeNEVertex, targetFormulaVertex)).toBe(true) - }) - - it('should use already existing named expression in other sheet when cut pasting formula', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - engine.addNamedExpression('expr', '=Sheet2!$A$1', 1) - - engine.cut(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.paste(adr('B1', 1)) - - expect(engine.getNamedExpressionFormula('expr')).toEqual(undefined) - expect(engine.getNamedExpressionFormula('expr', 0)).toEqual('=Sheet1!$A$1') - expect(engine.getNamedExpressionFormula('expr', 1)).toEqual('=Sheet2!$A$1') - expect(engine.getCellValue(adr('B1', 0))).toBe(null) - expect(engine.getCellValue(adr('B1', 1))).toEqual('bar') - // ensure edges are correct - const sourceScopeNEVertex = engine.dependencyGraph.fetchNamedExpressionVertex('expr', 0).vertex - const targetScopeNEVertex = engine.dependencyGraph.fetchNamedExpressionVertex('expr', 1).vertex - const targetFormulaVertex = engine.dependencyGraph.getCell(adr('B1', 1))! - expect(engine.dependencyGraph.existsEdge(sourceScopeNEVertex, targetFormulaVertex)).toBe(false) - expect(engine.dependencyGraph.existsEdge(targetScopeNEVertex, targetFormulaVertex)).toBe(true) - }) - - it('should use already existing named expression in other sheet when copying formula', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar']] - }) - - engine.addNamedExpression('expr', '=Sheet1!$A$1', 0) - engine.addNamedExpression('expr', '=Sheet2!$A$1', 1) - - engine.copy(AbsoluteCellRange.spanFrom(adr('B1'), 1, 1)) - engine.paste(adr('B1', 1)) - - expect(engine.getNamedExpressionFormula('expr')).toEqual(undefined) - expect(engine.getNamedExpressionFormula('expr', 0)).toEqual('=Sheet1!$A$1') - expect(engine.getNamedExpressionFormula('expr', 1)).toEqual('=Sheet2!$A$1') - expect(engine.getCellValue(adr('B1', 0))).toEqual('foo') - expect(engine.getCellValue(adr('B1', 1))).toEqual('bar') - // ensure edges are correct - const sourceScopeNEVertex = engine.dependencyGraph.fetchNamedExpressionVertex('expr', 0).vertex - const targetScopeNEVertex = engine.dependencyGraph.fetchNamedExpressionVertex('expr', 1).vertex - const targetFormulaVertex = engine.dependencyGraph.getCell(adr('B1', 1))! - expect(engine.dependencyGraph.existsEdge(sourceScopeNEVertex, targetFormulaVertex)).toBe(false) - expect(engine.dependencyGraph.existsEdge(targetScopeNEVertex, targetFormulaVertex)).toBe(true) - }) - }) - - describe('when created on initialization', () => { - it('should be possible to reference another sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo']], - 'Sheet2': [['bar']] - }, {}, [{ name: 'expr', expression: '=Sheet2!$A$1', scope: 0 }]) - - expect(engine.getNamedExpressionValue('expr', 0)).toEqual('bar') - }) - - it('should be possible to create named expressions with same name in two different scopes', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar', '=expr']] - }, {}, [ - { name: 'expr', expression: '=Sheet1!$A$1', scope: 0 }, - { name: 'expr', expression: '=Sheet2!$A$1', scope: 1 } - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual('foo') - expect(engine.getCellValue(adr('B1', 1))).toEqual('bar') - }) - - it('should be possible to access named expression only from its scope', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['foo', '=expr']], - 'Sheet2': [['bar', '=expr']] - }, {}, [{ name: 'expr', expression: '=Sheet1!$A$1', scope: 0 }]) - - expect(engine.getCellValue(adr('B1'))).toEqual('foo') - expect(engine.getCellValue(adr('B1', 1))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('expr'))) - }) - }) -}) - -describe('Named expressions - named ranges', () => { - describe('when created with addNamedExpression', () => { - it('should be possible to define simple range in named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['3'], - ]) - - engine.addNamedExpression('fooo', '=Sheet1!$A$1:Sheet1!$A$2') - engine.setCellContents(adr('B1'), [['=SUM(fooo)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual(4) - }) - - it('should be possible to define column range in named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['3'], - ]) - - engine.addNamedExpression('foo', '=Sheet1!$A:Sheet1!$A') - engine.addNamedExpression('bar', '=Sheet1!$A:$A') - engine.setCellContents(adr('B1'), [['=SUM(foo)']]) - engine.setCellContents(adr('B2'), [['=SUM(bar)']]) - - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('B2'))).toEqual(4) - }) - - it('should recalculate when named range changes definition', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ]) - - engine.addNamedExpression('fooo', '=Sheet1!$A:Sheet1!$A') - engine.setCellContents(adr('C1'), [['=SUM(fooo)']]) - engine.changeNamedExpression('fooo', '=Sheet1!$B:Sheet1!$B') - - expect(engine.getCellValue(adr('C1'))).toEqual(6) - }) - - it('should return array value of named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'], - ]) - - const changes = engine.addNamedExpression('fooo', '=TRANSPOSE(Sheet1!$A$1:Sheet1!$B$2)') - - expect(changes).toContainEqual(new ExportedNamedExpressionChange('fooo', [[1, 3], [2, 4]])) - }) - - it('should update automatically when row is added to the referenced range', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ]) - - engine.addNamedExpression('range', '=Sheet1!$A$1:$B$2') - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$B$2') - - engine.addRows(0, [1, 1]) - expect(engine.getSheetValues(0)).toEqual([[1, 2], [], [3, 4]]) - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$B$3') - }) - - it('should update automatically when column is added to the referenced range', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ]) - - engine.addNamedExpression('range', '=Sheet1!$A$1:$B$2') - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$B$2') - - engine.addColumns(0, [1, 1]) - expect(engine.getSheetValues(0)).toEqual([[1, null, 2], [3, null, 4]]) - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$C$2') - }) - }) - - describe('when created on initialization', () => { - it('should be possible to define simple range in named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(fooo)'], - ['3'], - ], {}, [{ name: 'fooo', expression: '=Sheet1!$A$1:Sheet1!$A$2' }]) - - expect(engine.getCellValue(adr('B1'))).toEqual(4) - }) - - it('should be possible to define column range in named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=SUM(foo)', '=SUM(bar)'], - ['3'], - ], {}, [ - { name: 'foo', expression: '=Sheet1!$A:Sheet1!$A' }, - { name: 'bar', expression: '=Sheet1!$A:$A' } - ]) - - expect(engine.getCellValue(adr('B1'))).toEqual(4) - expect(engine.getCellValue(adr('C1'))).toEqual(4) - }) - - it('should update automatically when row is added to the referenced range', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ], {}, [{ name: 'range', expression: '=Sheet1!$A$1:$B$2' }]) - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$B$2') - - engine.addRows(0, [1, 1]) - expect(engine.getSheetValues(0)).toEqual([[1, 2], [], [3, 4]]) - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$B$3') - }) - - it('should update automatically when column is added to the referenced range', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [3, 4], - ], {}, [{ name: 'range', expression: '=Sheet1!$A$1:$B$2' }]) - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$B$2') - - engine.addColumns(0, [1, 1]) - expect(engine.getSheetValues(0)).toEqual([[1, null, 2], [3, null, 4]]) - expect(engine.getNamedExpressionFormula('range')).toEqual('=Sheet1!$A$1:$C$2') - }) - }) -}) - -describe('Named expressions - options', () => { - describe('when created with addNamedExpression', () => { - it('should return named expression with empty options', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('foo', '=foo') - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=foo', - scope: undefined, - options: undefined - }) - }) - - it('should return named expression with empty options - scope provided', () => { - const engine = HyperFormula.buildFromArray([[]]) - - engine.addNamedExpression('foo', '=foo', 0) - - expect(engine.getNamedExpression('foo', 0)).toEqual({ - name: 'foo', - expression: '=foo', - scope: 0, - options: undefined - }) - }) - - it('should return undefined for non-existent named expression', () => { - const engine = HyperFormula.buildFromArray([[]]) - - engine.addNamedExpression('foo', '=foo') - - expect(engine.getNamedExpression('foo-bar')).toEqual(undefined) - }) - - it('should return named expression with options', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('foo', '=foo', undefined, {visible: false, comment: 'bar'}) - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=foo', - scope: undefined, - options: { - visible: false, - comment: 'bar' - } - }) - }) - - it('should preserve options after undo-redo', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('foo', '=foo', undefined, {visible: false, comment: 'bar'}) - - engine.undo() - engine.redo() - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=foo', - scope: undefined, - options: { - visible: false, - comment: 'bar' - } - }) - }) - - it('should change options of named expression', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('foo', '=foo', undefined, {visible: false, comment: 'foo'}) - - engine.changeNamedExpression('foo', '=bar', undefined, {visible: true, comment: 'bar'}) - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=bar', - scope: undefined, - options: { - visible: true, - comment: 'bar' - } - }) - }) - - it('should undo changing options of named expression', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('foo', '=foo', undefined, {visible: false, comment: 'foo'}) - engine.changeNamedExpression('foo', '=bar', undefined, {visible: true, comment: 'bar'}) - - engine.undo() - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=foo', - scope: undefined, - options: { - visible: false, - comment: 'foo' - } - }) - }) - - it('should undo-redo changing options of named expression', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('foo', '=foo', undefined, {visible: false, comment: 'foo'}) - engine.changeNamedExpression('foo', '=bar', undefined, {visible: true, comment: 'bar'}) - - engine.undo() - engine.redo() - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=bar', - scope: undefined, - options: { - visible: true, - comment: 'bar' - } - }) - }) - - it('should restore named expression with options', () => { - const engine = HyperFormula.buildEmpty() - - engine.addNamedExpression('foo', '=foo', undefined, {visible: false, comment: 'foo'}) - engine.removeNamedExpression('foo') - - engine.undo() - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=foo', - scope: undefined, - options: { - visible: false, - comment: 'foo' - } - }) - }) - }) - - describe('when created on initialization', () => { - it('should return named expression with empty options', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'foo', expression: '=foo' }]) - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=foo', - scope: undefined, - options: undefined - }) - }) - - it('should return named expression with empty options - scope provided', () => { - const engine = HyperFormula.buildFromArray([[]], {}, [{ name: 'foo', expression: '=foo', scope: 0 }]) - - expect(engine.getNamedExpression('foo', 0)).toEqual({ - name: 'foo', - expression: '=foo', - scope: 0, - options: undefined - }) - }) - - it('should return undefined for non-existent named expression', () => { - const engine = HyperFormula.buildFromArray([[]], {}, [{ name: 'foo', expression: '=foo' }]) - - expect(engine.getNamedExpression('foo-bar')).toEqual(undefined) - }) - - it('should return named expression with options', () => { - const engine = HyperFormula.buildEmpty({}, [{ name: 'foo', expression: '=foo', options: {visible: false, comment: 'bar'} }]) - - expect(engine.getNamedExpression('foo')).toEqual({ - name: 'foo', - expression: '=foo', - scope: undefined, - options: { - visible: false, - comment: 'bar' - } - }) - }) - }) -}) - -describe('Named expressions - actions at the Operations layer', () => { - - let operations: Operations - - beforeEach(() => { - const config = new Config() - const stats = new Statistics() - const namedExpressions = new NamedExpressions() - const functionRegistry = new FunctionRegistry(config) - const lazilyTransformingAstService = new LazilyTransformingAstService(stats) - const dependencyGraph = DependencyGraph.buildEmpty(lazilyTransformingAstService, config, functionRegistry, namedExpressions, stats) - const columnSearch = buildColumnSearchStrategy(dependencyGraph, config, stats) - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralHelper = new NumberLiteralHelper(config) - const cellContentParser = new CellContentParser(config, dateTimeHelper, numberLiteralHelper) - const parser = new ParserWithCaching( - config, - functionRegistry, - dependencyGraph.sheetReferenceRegistrar.ensureSheetRegistered.bind(dependencyGraph.sheetReferenceRegistrar) - ) - const arraySizePredictor = new ArraySizePredictor(config, functionRegistry) - operations = new Operations(config, dependencyGraph, columnSearch, cellContentParser, parser, stats, lazilyTransformingAstService, namedExpressions, arraySizePredictor) - }) - - it('should throw an error if you try and change an unknown named expression', () => { - operations.addNamedExpression('foo', 'foo') - const unknownNamedExpression = 'bar' - expect(() => { - operations.changeNamedExpressionExpression(unknownNamedExpression, '=125') - }).toThrow(new NamedExpressionDoesNotExistError(unknownNamedExpression)) - }) - - it('should throw an error if you try and change the expression to one that contains relative references', () => { - operations.addNamedExpression('foo', 'foo') - expect(() => { - operations.changeNamedExpressionExpression('foo', '=A2') - }).toThrow(new NoRelativeAddressesAllowedError()) - }) -}) - -describe('nested named expressions', () => { - describe('when created with addNamedExpression', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([['=ABCD']]) - engine.addNamedExpression('ABCD', '=EFGH') - engine.addNamedExpression('EFGH', 1) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - }) - - describe('when created on initialization', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([['=ABCD']], {}, [ - { name: 'ABCD', expression: '=EFGH' }, - { name: 'EFGH', expression: 1 } - ]) - expect(engine.getCellValue(adr('A1'))).toEqual(1) - }) - }) -}) - -describe('serialization', () => { - describe('when created with addNamedExpression', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['50'], - ['60']]) - engine.addNamedExpression('prettyName', '=Sheet1!$A$1+100') - engine.addNamedExpression('anotherPrettyName', '=Sheet1!$A$2+100') - engine.addNamedExpression('alsoPrettyName', '=Sheet1!$A$3+100', 0) - expect(engine.getAllNamedExpressionsSerialized()).toEqual([ - {name: 'prettyName', expression: '=Sheet1!$A$1+100', options: undefined, scope: undefined}, - {name: 'anotherPrettyName', expression: '=Sheet1!$A$2+100', options: undefined, scope: undefined}, - {name: 'alsoPrettyName', expression: '=Sheet1!$A$3+100', options: undefined, scope: 0} - ]) - }) - - it('should update scopes', () => { - const engine = HyperFormula.buildFromSheets({sheet1: [[]], sheet2: [[]], sheet3: [[]]}) - engine.addNamedExpression('prettyName', '=1', 0) - engine.addNamedExpression('anotherPrettyName', '=2', 1) - engine.addNamedExpression('alsoPrettyName', '=3', 2) - engine.removeSheet(1) - expect(engine.getAllNamedExpressionsSerialized()).toEqual([ - {name: 'prettyName', expression: '=1', scope: 0, options: undefined}, - {name: 'alsoPrettyName', expression: '=3', scope: 1, options: undefined} - ]) - }) - }) - - describe('when created on initialization', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['50'], - ['60']], {}, [ - { name: 'prettyName', expression: '=Sheet1!$A$1+100' }, - { name: 'anotherPrettyName', expression: '=Sheet1!$A$2+100' }, - { name: 'alsoPrettyName', expression: '=Sheet1!$A$3+100', scope: 0 } - ]) - expect(engine.getAllNamedExpressionsSerialized()).toEqual([ - {name: 'prettyName', expression: '=Sheet1!$A$1+100', options: undefined, scope: undefined}, - {name: 'anotherPrettyName', expression: '=Sheet1!$A$2+100', options: undefined, scope: undefined}, - {name: 'alsoPrettyName', expression: '=Sheet1!$A$3+100', options: undefined, scope: 0} - ]) - }) - - it('should update scopes', () => { - const engine = HyperFormula.buildFromSheets({sheet1: [[]], sheet2: [[]], sheet3: [[]]}, {}, [ - { name: 'prettyName', expression: '=1', scope: 0 }, - { name: 'anotherPrettyName', expression: '=2', scope: 1 }, - { name: 'alsoPrettyName', expression: '=3', scope: 2 } - ]) - engine.removeSheet(1) - expect(engine.getAllNamedExpressionsSerialized()).toEqual([ - {name: 'prettyName', expression: '=1', scope: 0, options: undefined}, - {name: 'alsoPrettyName', expression: '=3', scope: 1, options: undefined} - ]) - }) - }) -}) - -describe('getNamedExpressionsFromFormula method', () => { - describe('when created with addNamedExpression', () => { - it('should return an empty array when called with a formula that has no named expressions', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expect(engine.getNamedExpressionsFromFormula('="test"')).toEqual([]) - }) - - it('should return the existing named expressions', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - engine.addNamedExpression('bar', '=42') - - expectArrayWithSameContent(engine.getNamedExpressionsFromFormula('=foo+bar*2'), ['foo', 'bar']) - }) - - it('should return the non-existing named expressions', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expectArrayWithSameContent(engine.getNamedExpressionsFromFormula('=bar+baz*2'), ['bar', 'baz']) - }) - - it('should return each named expression only once', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expect(engine.getNamedExpressionsFromFormula('=foo+foo*2')).toEqual(['foo']) - }) - - it('should throw the ExpectedValueOfTypeError exception for input of wrong type', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expect(() => engine.getNamedExpressionsFromFormula(42 as any)).toThrow(new ExpectedValueOfTypeError('string', 'formulaString')) - }) - - it('should throw the NotAFormulaError exception for a string that doesn\'t start with "="', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expect(() => engine.getNamedExpressionsFromFormula('foo')).toThrow(new NotAFormulaError()) - }) - - it('should throw an exception for empty formula', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expect(() => engine.getNamedExpressionsFromFormula('')).toThrow(new NotAFormulaError()) - }) - - it('should return an empty array when called with a formula with an error literal', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expect(engine.getNamedExpressionsFromFormula('=#VALUE!')).toEqual([]) - }) - - it('should throw the NotAFormulaError exception for an unparsable formula', () => { - const engine = HyperFormula.buildEmpty() - engine.addNamedExpression('foo', '=42') - - expect(() => engine.getNamedExpressionsFromFormula('=#FOO!')).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula('=100%%*foo')).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula('=@foo')).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula("=foo'bar")).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula('=\u00A0foo')).toThrow(new NotAFormulaError()) - }) - }) - - describe('when created on initialization', () => { - it('should return an empty array when called with a formula that has no named expressions', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expect(engine.getNamedExpressionsFromFormula('="test"')).toEqual([]) - }) - - it('should return the existing named expressions', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - { name: 'bar', expression: '=42' }, - ]) - - expectArrayWithSameContent(engine.getNamedExpressionsFromFormula('=foo+bar*2'), ['foo', 'bar']) - }) - - it('should return the non-existing named expressions', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expectArrayWithSameContent(engine.getNamedExpressionsFromFormula('=bar+baz*2'), ['bar', 'baz']) - }) - - it('should return each named expression only once', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expect(engine.getNamedExpressionsFromFormula('=foo+foo*2')).toEqual(['foo']) - }) - - it('should throw the ExpectedValueOfTypeError exception for input of wrong type', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expect(() => engine.getNamedExpressionsFromFormula(42 as any)).toThrow(new ExpectedValueOfTypeError('string', 'formulaString')) - }) - - it('should throw the NotAFormulaError exception for a string that doesn\'t start with "="', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expect(() => engine.getNamedExpressionsFromFormula('foo')).toThrow(new NotAFormulaError()) - }) - - it('should throw an exception for empty formula', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expect(() => engine.getNamedExpressionsFromFormula('')).toThrow(new NotAFormulaError()) - }) - - it('should return an empty array when called with a formula with an error literal', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expect(engine.getNamedExpressionsFromFormula('=#VALUE!')).toEqual([]) - }) - - it('should throw the NotAFormulaError exception for an unparsable formula', () => { - const engine = HyperFormula.buildEmpty({}, [ - { name: 'foo', expression: '=42' }, - ]) - - expect(() => engine.getNamedExpressionsFromFormula('=#FOO!')).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula('=100%%*foo')).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula('=@foo')).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula("=foo'bar")).toThrow(new NotAFormulaError()) - expect(() => engine.getNamedExpressionsFromFormula('=\u00A0foo')).toThrow(new NotAFormulaError()) - }) - }) -}) diff --git a/test/unit/null-compatibility.spec.ts b/test/unit/null-compatibility.spec.ts deleted file mode 100644 index 8303d2e0e5..0000000000 --- a/test/unit/null-compatibility.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {HyperFormula} from '../../src' -import {adr} from './testUtils' - -describe('null compatibility', () => { - it('should evaluate empty reference to null', () => { - const engine = HyperFormula.buildFromArray([['=A2']], {evaluateNullToZero: false}) - expect(engine.getCellValue(adr('A1'))).toBeNull() - expect(engine.getCellValue(adr('A2'))).toBeNull() - }) - - it('should evaluate empty reference to 0', () => { - const engine = HyperFormula.buildFromArray([['=A2']], {evaluateNullToZero: true}) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toBeNull() - }) - - it('should evaluate if to null', () => { - const engine = HyperFormula.buildFromArray([['=IF(TRUE(),A2)']], {evaluateNullToZero: false}) - expect(engine.getCellValue(adr('A1'))).toBeNull() - expect(engine.getCellValue(adr('A2'))).toBeNull() - }) - - it('should evaluate if to 0', () => { - const engine = HyperFormula.buildFromArray([['=IF(TRUE(),A2)']], {evaluateNullToZero: true}) - expect(engine.getCellValue(adr('A1'))).toEqual(0) - expect(engine.getCellValue(adr('A2'))).toBeNull() - }) - - it('should evaluate isblank with null', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2', '=ISBLANK(A1)'], - [null, '=ISBLANK(A2)'] - ], {evaluateNullToZero: false}) - expect(engine.getCellValue(adr('B1'))).toEqual(true) - expect(engine.getCellValue(adr('B2'))).toEqual(true) - }) - - it('should evaluate isblank with 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2', '=ISBLANK(A1)'], - [null, '=ISBLANK(A2)'] - ], {evaluateNullToZero: true}) - expect(engine.getCellValue(adr('B1'))).toEqual(false) - expect(engine.getCellValue(adr('B2'))).toEqual(true) - }) -}) diff --git a/test/unit/optional-parameters.spec.ts b/test/unit/optional-parameters.spec.ts deleted file mode 100644 index 9e54a6fca4..0000000000 --- a/test/unit/optional-parameters.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {ErrorMessage} from '../../src/error-message' -import {InterpreterState} from '../../src/interpreter/InterpreterState' -import {FunctionArgumentType, FunctionPlugin, FunctionPluginTypecheck} from '../../src/interpreter/plugin/FunctionPlugin' -import {ProcedureAst} from '../../src/parser' -import {adr, detailedError} from './testUtils' - -class FooPlugin extends FunctionPlugin implements FunctionPluginTypecheck { - public static implementedFunctions = { - 'FOO': { - method: 'foo', - parameters: [ - {argumentType: FunctionArgumentType.STRING, defaultValue: 'default1'}, - {argumentType: FunctionArgumentType.STRING, defaultValue: 'default2'}, - ], - }, - } - - public foo(ast: ProcedureAst, state: InterpreterState) { - return this.runFunction(ast.args, state, this.metadata('FOO'), - (arg1: string, arg2: string) => arg1 + '+' + arg2 - ) - } -} - -describe('Nonexistent metadata', () => { - it('should work for function', () => { - HyperFormula.getLanguage('enGB').extendFunctions({FOO: 'FOO'}) - const engine = HyperFormula.buildFromArray([ - ['=foo(1,2)'], - ['=foo(,2)'], - ['=foo( ,2)'], - ['=foo(1,)'], - ['=foo( , )'], - ['=foo(1)'], - ['=foo()'], - ], {functionPlugins: [FooPlugin]}) - - expect(engine.getCellValue(adr('A1'))).toBe('1+2') - expect(engine.getCellValue(adr('A2'))).toBe('+2') - expect(engine.getCellValue(adr('A3'))).toBe('+2') - expect(engine.getCellValue(adr('A4'))).toBe('1+') - expect(engine.getCellValue(adr('A5'))).toBe('+') - expect(engine.getCellValue(adr('A6'))).toBe('1+default2') - expect(engine.getCellValue(adr('A7'))).toBe('default1+default2') - }) - - it('log fails with coerce to 0', () => { - const engine = HyperFormula.buildFromArray([ - ['=LOG(10,)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NUM, ErrorMessage.ValueSmall)) - }) - - it('other function coerce EmptyValue', () => { - const engine = HyperFormula.buildFromArray([ - ['=DATE(,1,1900)'], - ['=SUM(,1)'], - ['=CONCATENATE(,"abcd")'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual(1901) - expect(engine.getCellValue(adr('A2'))).toEqual(1) - expect(engine.getCellValue(adr('A3'))).toEqual('abcd') - }) - -}) diff --git a/test/unit/parser/apostrophe.spec.ts b/test/unit/parser/apostrophe.spec.ts deleted file mode 100644 index c616111cf8..0000000000 --- a/test/unit/parser/apostrophe.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {CellValueDetailedType, HyperFormula} from '../../../src' -import {adr} from '../testUtils' - -describe('When value is prepend with an apostrophe', () => { - it('treats numeric value as a string', () => { - const engine = HyperFormula.buildFromArray([ - ["'001572"], - ['=A1'] - ]) - - expect(engine.getCellValue(adr('A1'))).toEqual('001572') - expect(engine.getCellValue(adr('A2'))).toEqual('001572') - expect(engine.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.STRING) - }) -}) diff --git a/test/unit/parser/boolean-operators.spec.ts b/test/unit/parser/boolean-operators.spec.ts deleted file mode 100644 index 92473601d5..0000000000 --- a/test/unit/parser/boolean-operators.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {Config} from '../../../src/Config' -import { - AstNodeType, - EqualsOpAst, - GreaterThanOpAst, - GreaterThanOrEqualOpAst, - LessThanOpAst, - LessThanOrEqualOpAst, - NotEqualOpAst, -} from '../../../src/parser' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Parser - Boolean operators', () => { - it('Equals operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1=2', adr('A1')).ast as EqualsOpAst - - expect(ast.type).toBe(AstNodeType.EQUALS_OP) - }) - - it('Not equal operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1<>2', adr('A1')).ast as NotEqualOpAst - - expect(ast.type).toBe(AstNodeType.NOT_EQUAL_OP) - }) - - it('Greater than operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1>2', adr('A1')).ast as GreaterThanOpAst - - expect(ast.type).toBe(AstNodeType.GREATER_THAN_OP) - }) - - it('Less than operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1<2', adr('A1')).ast as LessThanOpAst - - expect(ast.type).toBe(AstNodeType.LESS_THAN_OP) - }) - - it('Greater than or equal operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1>=2', adr('A1')).ast as GreaterThanOrEqualOpAst - - expect(ast.type).toBe(AstNodeType.GREATER_THAN_OR_EQUAL_OP) - }) - - it('Less than or equal operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1<=2', adr('A1')).ast as LessThanOrEqualOpAst - - expect(ast.type).toBe(AstNodeType.LESS_THAN_OR_EQUAL_OP) - }) - - it('Boolean operator with more complex childs', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1+2=1+2*6', adr('A1')).ast as EqualsOpAst - - expect(ast.type).toBe(AstNodeType.EQUALS_OP) - expect(ast.left.type).toBe(AstNodeType.PLUS_OP) - expect(ast.right.type).toBe(AstNodeType.PLUS_OP) - }) -}) diff --git a/test/unit/parser/cell-address-from-string.spec.ts b/test/unit/parser/cell-address-from-string.spec.ts deleted file mode 100644 index 7a19e8f3e9..0000000000 --- a/test/unit/parser/cell-address-from-string.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { AlwaysDense } from '../../../src' -import {AddressMapping, SheetMapping, SheetReferenceRegistrar} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB} from '../../../src/i18n/languages' -import {CellAddress, cellAddressFromString} from '../../../src/parser' -import {adr} from '../testUtils' - -describe('cellAddressFromString', () => { - let sheetMapping: SheetMapping - let addressMapping: AddressMapping - let resolveSheetReference: (sheetName: string) => number - beforeEach(() => { - sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - addressMapping = new AddressMapping(new AlwaysDense()) - const registrar = new SheetReferenceRegistrar(sheetMapping, addressMapping) - resolveSheetReference = registrar.ensureSheetRegistered.bind(registrar) - }) - - it('is zero based', () => { - expect(cellAddressFromString('A1', adr('A1'), resolveSheetReference)).toEqual(CellAddress.relative(0, 0)) - }) - - it('works for bigger rows', () => { - expect(cellAddressFromString('A123', adr('A1'), resolveSheetReference)).toEqual(CellAddress.relative(0, 122)) - }) - - it('one letter', () => { - expect(cellAddressFromString('Z1', adr('A1'), resolveSheetReference)).toEqual(CellAddress.relative(25, 0)) - }) - - it('last letter is Z', () => { - expect(cellAddressFromString('AA1', adr('A1'), resolveSheetReference)).toEqual(CellAddress.relative(26, 0)) - }) - - it('works for many letters', () => { - expect(cellAddressFromString('ABC1', adr('A1'), resolveSheetReference)).toEqual(CellAddress.relative(730, 0)) - }) - - it('is not case sensitive', () => { - expect(cellAddressFromString('abc1', adr('A1'), resolveSheetReference)).toEqual(CellAddress.relative(730, 0)) - }) - - it('when sheet is missing, its took from base address', () => { - expect(cellAddressFromString('B3', adr('A1', 42), resolveSheetReference)).toEqual(CellAddress.relative(1, 2)) - }) - - it('can into sheets', () => { - const sheet1 = sheetMapping.addSheet('Sheet1') - const sheet2 = sheetMapping.addSheet('Sheet2') - const sheet3 = sheetMapping.addSheet('~`!@#$%^&*()_-+_=/|?{}[]\"') - - expect(cellAddressFromString('Sheet1!B3', adr('A1', sheet1), resolveSheetReference)).toEqual(CellAddress.relative(1, 2, sheet1)) - expect(cellAddressFromString('Sheet2!B3', adr('A1', sheet1), resolveSheetReference)).toEqual(CellAddress.relative(1, 2, sheet2)) - expect(cellAddressFromString("'~`!@#$%^&*()_-+_=/|?{}[]\"'!B3", adr('A1', sheet1), resolveSheetReference)).toEqual(CellAddress.relative(1, 2, sheet3)) - }) - - it('returns undefined when sheet resolver fails', () => { - const failingResolver = () => undefined - - expect(cellAddressFromString('Ghost!A1', adr('A1'), failingResolver)).toBeUndefined() - }) -}) diff --git a/test/unit/parser/common.ts b/test/unit/parser/common.ts deleted file mode 100644 index 86e66780c1..0000000000 --- a/test/unit/parser/common.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { AlwaysDense } from '../../../src' -import {Config} from '../../../src/Config' -import {AddressMapping, SheetMapping, SheetReferenceRegistrar} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB} from '../../../src/i18n/languages' -import {FunctionRegistry} from '../../../src/interpreter/FunctionRegistry' -import {ParserWithCaching} from '../../../src/parser' - -export function buildEmptyParserWithCaching(config: Config, sheetMapping?: SheetMapping, addressMapping?: AddressMapping): ParserWithCaching { - sheetMapping = sheetMapping || new SheetMapping(buildTranslationPackage(enGB)) - addressMapping = addressMapping || new AddressMapping(new AlwaysDense()) - const registrar = new SheetReferenceRegistrar(sheetMapping, addressMapping) - return new ParserWithCaching( - config, - new FunctionRegistry(config), - registrar.ensureSheetRegistered.bind(registrar) - ) -} diff --git a/test/unit/parser/compute-hash-from-ast.spec.ts b/test/unit/parser/compute-hash-from-ast.spec.ts deleted file mode 100644 index ccc203178b..0000000000 --- a/test/unit/parser/compute-hash-from-ast.spec.ts +++ /dev/null @@ -1,223 +0,0 @@ -import {HyperFormula} from '../../../src' -import {Config} from '../../../src/Config' -import {SheetMapping} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB, plPL} from '../../../src/i18n/languages' -import {buildLexerConfig, FormulaLexer} from '../../../src/parser' -import {adr, unregisterAllLanguages} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Compute hash from ast', () => { - beforeEach(() => { - unregisterAllLanguages() - HyperFormula.registerLanguage(plPL.langCode, plPL) - HyperFormula.registerLanguage(enGB.langCode, enGB) - }) - - const config = new Config() - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const lexer = new FormulaLexer(buildLexerConfig(config)) - const parser = buildEmptyParserWithCaching(config, sheetMapping) - - function expectHashFromAstMatchHashFromTokens(formula: string) { - const baseAddress = adr('A1') - const ast = parser.parse(formula, baseAddress).ast - const lexerResult = lexer.tokenizeFormula(formula) - const hashFromTokens = parser.computeHashFromTokens(lexerResult.tokens, baseAddress) - - const hashFromAst = parser.computeHashFromAst(ast) - - expect(hashFromAst).toEqual(hashFromTokens) - } - - it('literals', () => { - const formula = '=CONCATENATE("foo", 42.34)' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('function call', () => { - const formula = '=SUM(1, 2, 3)' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('function call - case insensitive', () => { - const formula = '=SuM(1,2,3)' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('simple addreess', () => { - const formula = '=Sheet1!A1' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('absolute col', () => { - const formula = '=Sheet1!$A1' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('absolute row addreess', () => { - const formula = '=Sheet1!A$1' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('absolute address', () => { - const formula = '=Sheet1!$A$1' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('cell range', () => { - const formula = '=$A$1:B$2' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('cell range with sheet on the left', () => { - const formula = '=Sheet1!A5:B16' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('cell range with sheet on both sides', () => { - const formula = '=Sheet1!A5:Sheet2!B16' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('column range', () => { - const formula = '=$A:B' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('column range with sheet on the left', () => { - const formula = '=Sheet1!A:B' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('column range with sheet on both sides', () => { - const formula = '=Sheet1!A:Sheet2!B' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('row range', () => { - const formula = '=$1:2' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('row range with sheet on the left', () => { - const formula = '=Sheet1!1:2' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('row range with sheet on both sides', () => { - const formula = '=Sheet1!1:Sheet2!2' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('ops', () => { - const formula = '=-1+1-1*1/1^1&1=1<>1<1<=1>1<1%' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('parenthesis', () => { - const formula = '=-1*(-2)*(3+4)+5' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('nested parenthesis', () => { - const formula = '=-(-(3+4))' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('cell ref between strings', () => { - const formula = '="A5"+A4+"A6"' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('cell ref in string with escape', () => { - const formula = '="fdsaf\\"A5"' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('procedure with error literal', () => { - const formula = '=#DIV/0!' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('reference to not existing sheet', () => { - const formula = '=Sheet3!A1' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('procedure hash using canonical name', () => { - const config = new Config({language: 'plPL'}) - const sheetMapping = new SheetMapping(buildTranslationPackage(plPL)) - sheetMapping.addSheet('Sheet1') - const lexer = new FormulaLexer(buildLexerConfig(config)) - const parser = buildEmptyParserWithCaching(config, sheetMapping) - - const formula = '=SUMA(A1)' - const address = adr('A1') - const ast = parser.parse(formula, address).ast - const lexerResult = lexer.tokenizeFormula(formula) - const hashFromTokens = parser.computeHashFromTokens(lexerResult.tokens, address) - const hash = parser.computeHashFromAst(ast) - - expect(hash).toEqual(hashFromTokens) - }) - - it('procedure name with missing translation', () => { - const config = new Config({language: 'plPL'}) - const sheetMapping = new SheetMapping(buildTranslationPackage(plPL)) - sheetMapping.addSheet('Sheet1') - const lexer = new FormulaLexer(buildLexerConfig(config)) - const parser = buildEmptyParserWithCaching(config, sheetMapping) - - const formula = '=FooBAR(A1)' - const address = adr('A1') - const ast = parser.parse(formula, address).ast - const lexerResult = lexer.tokenizeFormula(formula) - const hashFromTokens = parser.computeHashFromTokens(lexerResult.tokens, address) - const hash = parser.computeHashFromAst(ast) - - expect(hash).toEqual(hashFromTokens) - }) - - it('should work with whitespaces', () => { - const formula = '= - 1 + 2 / 3 - 4 % * (1 + 2 ) + SUM( A1, A1 : A2 ) + #DIV/0!' - const address = adr('A1') - const ast = parser.parse(formula, address).ast - const hash = parser.computeHashFromAst(ast) - expect(hash).toEqual('= - 1 + 2 / 3 - 4 % * (1 + 2 ) + SUM( #0R0, #0R0:#1R0 ) + #DIV/0!') - }) - - it('should skip whitespaces before function args separators', () => { - const formula = '=SUM(A1 , A2)' - const address = adr('A1') - const ast = parser.parse(formula, address).ast - const hash = parser.computeHashFromAst(ast) - expect(hash).toEqual('=SUM(#0R0, #1R0)') - }) - - it('should not skip whitespaces when there is empty arg', () => { - const formula = '=PV(1 ,2,3, ,A2)' - expectHashFromAstMatchHashFromTokens(formula) - }) - - it('should work with decimal separator', () => { - const config = new Config({decimalSeparator: ',', functionArgSeparator: ';'}) - const sheetMapping = new SheetMapping(buildTranslationPackage(plPL)) - sheetMapping.addSheet('Sheet1') - const lexer = new FormulaLexer(buildLexerConfig(config)) - const parser = buildEmptyParserWithCaching(config, sheetMapping) - - const formula = '=1+123,456' - const address = adr('A1') - const ast = parser.parse(formula, address).ast - - const lexerResult = lexer.tokenizeFormula(formula) - const hashFromTokens = parser.computeHashFromTokens(lexerResult.tokens, address) - const hash = parser.computeHashFromAst(ast) - - expect(hash).toEqual(formula) - expect(hash).toEqual(hashFromTokens) - }) -}) diff --git a/test/unit/parser/compute-hash-from-tokens.spec.ts b/test/unit/parser/compute-hash-from-tokens.spec.ts deleted file mode 100644 index 1407f0db2b..0000000000 --- a/test/unit/parser/compute-hash-from-tokens.spec.ts +++ /dev/null @@ -1,208 +0,0 @@ -import {HyperFormula} from '../../../src' -import {SimpleCellAddress} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {SheetMapping} from '../../../src/DependencyGraph' -import {enGB, plPL} from '../../../src/i18n/languages' -import {buildLexerConfig, FormulaLexer} from '../../../src/parser' -import {adr, unregisterAllLanguages} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('computeHashFromTokens', () => { - const computeFunc = (code: string, address: SimpleCellAddress, language: string = 'enGB'): string => { - const config = new Config({language}) - const sheetMapping = new SheetMapping(HyperFormula.getLanguage(language)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(config, sheetMapping) - const tokens = new FormulaLexer(buildLexerConfig(config)).tokenizeFormula(code).tokens - return parser.computeHashFromTokens(tokens, address) - } - beforeEach(() => { - unregisterAllLanguages() - HyperFormula.registerLanguage(plPL.langCode, plPL) - HyperFormula.registerLanguage(enGB.langCode, enGB) - }) - - it('simple case', () => { - const code = '=42' - - expect(computeFunc(code, adr('B2'))).toEqual('=42') - }) - - it('cell relative reference', () => { - const code = '=A5' - - expect(computeFunc(code, adr('B2'))).toEqual('=#3R-1') - }) - - it('cell absolute reference', () => { - const code = '=$A$5' - - expect(computeFunc(code, adr('B2'))).toEqual('=#4A0') - }) - - it('cell absolute col reference', () => { - const code = '=$A5' - - expect(computeFunc(code, adr('B2'))).toEqual('=#3AC0') - }) - - it('cell absolute row reference', () => { - const code = '=A$5' - - expect(computeFunc(code, adr('B2'))).toEqual('=#4AR-1') - }) - - it('more addresses', () => { - const code = '=A5+A7' - - expect(computeFunc(code, adr('B2'))).toEqual('=#3R-1+#5R-1') - }) - - it('cell ref in string', () => { - const code = '="A5"' - - expect(computeFunc(code, adr('B2'))).toEqual('="A5"') - }) - - it('cell ref between strings', () => { - const code = '="A5"+A4+"A6"' - - expect(computeFunc(code, adr('B2'))).toEqual('="A5"+#2R-1+"A6"') - }) - - it('cell ref in string with escape', () => { - const code = '="fdsaf\\"A5"' - - expect(computeFunc(code, adr('B2'))).toEqual('="fdsaf\\"A5"') - }) - - it('cell ref to not exsiting sheet', () => { - const code = '=Sheet3!A1' - - expect(computeFunc(code, adr('B2'))).toBe('=#2#-1R-1') - }) - - it('cell range', () => { - const code = '=A5:B16' - - expect(computeFunc(code, adr('B2'))).toEqual('=#3R-1:#14R0') - }) - - it('cell range with sheet on the left', () => { - const code = '=Sheet1!A5:B16' - - expect(computeFunc(code, adr('B2'))).toEqual('=#0#3R-1:#14R0') - }) - - it('cell range with sheet on both sides', () => { - const code = '=Sheet1!A5:Sheet2!B16' - - expect(computeFunc(code, adr('B2'))).toEqual('=#0#3R-1:#1#14R0') - }) - - it('column range', () => { - const code = '=A:$B' - - expect(computeFunc(code, adr('B2'))).toEqual('=#COLR-1:#COLA1') - }) - - it('column range with sheet on the left', () => { - const code = '=Sheet1!A:B' - - expect(computeFunc(code, adr('B2'))).toEqual('=#0#COLR-1:#COLR0') - }) - - it('column range with sheet on both sides', () => { - const code = '=Sheet1!A:Sheet2!B' - - expect(computeFunc(code, adr('B2'))).toEqual('=#0#COLR-1:#1#COLR0') - }) - - it('row range', () => { - const code = '=1:$2' - - expect(computeFunc(code, adr('B2'))).toEqual('=#ROWR-1:#ROWA1') - }) - - it('row range with sheet on the left', () => { - const code = '=Sheet1!1:2' - - expect(computeFunc(code, adr('B2'))).toEqual('=#0#ROWR-1:#ROWR0') - }) - - it('row range with sheet on both sides', () => { - const code = '=Sheet1!1:Sheet2!2' - - expect(computeFunc(code, adr('B2'))).toEqual('=#0#ROWR-1:#1#ROWR0') - }) - - it('do not ignores whitespace', () => { - const code = '= 42' - - expect(computeFunc(code, adr('B2'))).toEqual('= 42') - }) - - it('different hash for formulas with different namespace', () => { - const code1 = '= 42 ' - const code2 = '=42' - - const result1 = computeFunc(code1, adr('B2')) - const result2 = computeFunc(code2, adr('B2')) - expect(result1).not.toEqual(result2) - }) - - it('support sheets', () => { - const code = '=Sheet2!A5' - - expect(computeFunc(code, adr('B2'))).toEqual('=#1#3R-1') - }) - - it('function call names are normalized', () => { - const code = '=rAnd()' - - expect(computeFunc(code, adr('B2'))).toEqual('=RAND()') - }) - - it('function call in canonical form', () => { - const code = '=SUMA()' - - expect(computeFunc(code, adr('B2'), 'plPL')).toEqual('=SUM()') - }) - - it('function call when missing translation', () => { - const code = '=fooBAR()' - - expect(computeFunc(code, adr('B2'), 'plPL')).toEqual('=FOOBAR()') - }) - - it('should work with whitespaces', () => { - const formula = '= - 1 + 2 / 3 - 4 % * (1 + 2 ) + SUM( Sheet1!A1, A1:A2 )' - const hash = computeFunc(formula, adr('A1')) - expect(hash).toEqual('= - 1 + 2 / 3 - 4 % * (1 + 2 ) + SUM( #0#0R0, #0R0:#1R0 )') - }) - - it('should skip whitespaces inside range', () => { - const formula = '=SUM( A1 : A2 )' - const hash = computeFunc(formula, adr('A1')) - expect(hash).toEqual('=SUM( #0R0:#1R0 )') - }) - - it('should skip trailing whitespace', () => { - const formula = '=1 ' - const hash = computeFunc(formula, adr('A1')) - expect(hash).toEqual('=1') - }) - - it('should skip whitespaces before function args separators', () => { - const formula = '=SUM(A1 , A2)' - const hash = computeFunc(formula, adr('A1')) - expect(hash).toEqual('=SUM(#0R0, #1R0)') - }) - - it('should not skip whitespaces when there is empty arg', () => { - const formula = '=PV(A1 ,2,3, ,A2)' - const hash = computeFunc(formula, adr('A1')) - expect(hash).toEqual('=PV(#0R0,2,3, ,#1R0)') - }) -}) diff --git a/test/unit/parser/concatenate-operator.spec.ts b/test/unit/parser/concatenate-operator.spec.ts deleted file mode 100644 index 4e4355b007..0000000000 --- a/test/unit/parser/concatenate-operator.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {Config} from '../../../src/Config' -import {AstNodeType, ConcatenateOpAst, ProcedureAst} from '../../../src/parser' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Parser - Concatenate operators', () => { - it('Greater than operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('="a"&"b"', adr('A1')).ast as ConcatenateOpAst - expect(ast.type).toBe(AstNodeType.CONCATENATE_OP) - expect(ast.left.type).toBe(AstNodeType.STRING) - expect(ast.left.type).toBe(AstNodeType.STRING) - }) - - it('Greater than operator as function parameter', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=CONCATENATE("="&A6,"foo")', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.args[0]!.type).toBe(AstNodeType.CONCATENATE_OP) - }) -}) diff --git a/test/unit/parser/decimal.spec.ts b/test/unit/parser/decimal.spec.ts deleted file mode 100644 index 65ba2b159d..0000000000 --- a/test/unit/parser/decimal.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {ErrorMessage} from '../../../src/error-message' -import {adr, detailedError} from '../testUtils' - -describe('decimal parsing', () => { - it('parsing decimal without leading zero', () => { - const engine = HyperFormula.buildFromArray([ - ['.1', '=.1'], - ['-.1', '=-.1'], - ['+.1', '=+.1'], - ['+.1', '=+.1+.2'], - ['=SUM(A1:A4, 0.3, .3)', '=SUM(B1:B4)'], - ['.1.4', '=..1'], - ['1.', '=1.'], - ['1e1', '=1e1'], - ['1e+1', '=1e+1'], - ['1e-1', '=1e-1'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0.1) - expect(engine.getCellValue(adr('B1'))).toBe(0.1) - expect(engine.getCellValue(adr('A2'))).toBe(-0.1) - expect(engine.getCellValue(adr('B2'))).toBe(-0.1) - expect(engine.getCellValue(adr('A3'))).toBe(0.1) - expect(engine.getCellValue(adr('B3'))).toBe(0.1) - expect(engine.getCellValue(adr('A4'))).toBe(0.1) - expect(engine.getCellValue(adr('B4'))).toBe(0.3) - expect(engine.getCellValue(adr('A5'))).toBe(0.8) - expect(engine.getCellValue(adr('B5'))).toBe(0.4) - expect(engine.getCellValue(adr('A6'))).toBe('.1.4') - expect(engine.getCellValue(adr('B6'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - expect(engine.getCellValue(adr('A7'))).toBe(1) - expect(engine.getCellValue(adr('B7'))).toBe(1) - expect(engine.getCellValue(adr('A8'))).toBe(10) - expect(engine.getCellValue(adr('B8'))).toBe(10) - expect(engine.getCellValue(adr('A9'))).toBe(10) - expect(engine.getCellValue(adr('B9'))).toBe(10) - expect(engine.getCellValue(adr('A10'))).toBe(0.1) - expect(engine.getCellValue(adr('B10'))).toBe(0.1) - }) -}) diff --git a/test/unit/parser/error-literals.spec.ts b/test/unit/parser/error-literals.spec.ts deleted file mode 100644 index af940fc9d1..0000000000 --- a/test/unit/parser/error-literals.spec.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {HyperFormula} from '../../../src' -import {ErrorType} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import {SheetMapping} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB, plPL} from '../../../src/i18n/languages' -import {AstNodeType, ErrorAst, ParsingErrorType} from '../../../src/parser' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Parsing error literals', () => { - it('should parse error literals', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=#VALUE!', adr('A1')).ast as ErrorAst - expect(ast.type).toBe(AstNodeType.ERROR) - expect(ast.error.type).toEqual(ErrorType.VALUE) - }) - - it('should not parse #LIC! as license error', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=#LIC!', adr('A1')).ast as ErrorAst - expect(ast.type).toBe(AstNodeType.ERROR) - expect(ast.error.type).toEqual(ErrorType.ERROR) - }) - - it('should parse error literals with ?', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=#NAME?', adr('A1')).ast as ErrorAst - expect(ast.type).toBe(AstNodeType.ERROR) - expect(ast.error.type).toEqual(ErrorType.NAME) - }) - - it('should parse error literals with slashes', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=#N/A', adr('A1')).ast as ErrorAst - expect(ast.type).toBe(AstNodeType.ERROR) - expect(ast.error.type).toEqual(ErrorType.NA) - }) - - it('should parse error in other languages', () => { - HyperFormula.registerLanguage('plPL', plPL) - const parser = buildEmptyParserWithCaching(new Config({language: 'plPL'}), new SheetMapping(buildTranslationPackage(plPL))) - const ast = parser.parse('=#ARG!', adr('A1')).ast as ErrorAst - expect(ast.type).toBe(AstNodeType.ERROR) - expect(ast.error.type).toEqual(ErrorType.VALUE) - }) - - it('should parse #DIV/0!', () => { - const parser = buildEmptyParserWithCaching(new Config({language: 'enGB'}), new SheetMapping(buildTranslationPackage(enGB))) - const ast = parser.parse('=#DIV/0!', adr('A1')).ast as ErrorAst - expect(ast.type).toBe(AstNodeType.ERROR) - expect(ast.error.type).toEqual(ErrorType.DIV_BY_ZERO) - }) - - it('should return parser error', () => { - const parser = buildEmptyParserWithCaching(new Config({language: 'enGB'}), new SheetMapping(buildTranslationPackage(enGB))) - const {ast, errors} = parser.parse('=#UNKNOWN!', adr('A1')) - expect(ast.type).toBe(AstNodeType.ERROR) - expect(errors[0].type).toBe(ParsingErrorType.ParserError) - expect(errors[0].message).toBe('Unknown error literal') - }) -}) diff --git a/test/unit/parser/offset-translation.spec.ts b/test/unit/parser/offset-translation.spec.ts deleted file mode 100644 index a75c6bef81..0000000000 --- a/test/unit/parser/offset-translation.spec.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { HyperFormula } from '../../../src' -import {CellError, ErrorType} from '../../../src/Cell' -import {Config} from '../../../src/Config' -import { SheetMapping } from '../../../src/DependencyGraph' -import {ErrorMessage} from '../../../src/error-message' -import { buildTranslationPackage } from '../../../src/i18n' -import { enUS } from '../../../src/i18n/languages' -import {AstNodeType, CellAddress, CellRangeAst, CellReferenceAst, ErrorAst} from '../../../src/parser' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Parser - OFFSET to reference translation', () => { - it('OFFSET parsing into cell reference', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=OFFSET(F16, 0, 0)', adr('B3', 1)).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference).toEqual(CellAddress.relative(4, 13)) - }) - - it('OFFSET parsing into cell reference with row shift', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=OFFSET(F16, 1, 0)', adr('B3', 1)).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference).toEqual(CellAddress.relative(4, 14)) - }) - - it('OFFSET parsing into cell reference with negative row shift', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=OFFSET(C3, -1, 0)', adr('B2')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference).toEqual(CellAddress.relative(1, 0)) - }) - - it('OFFSET parsing into cell reference with column shift', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=OFFSET(F16, 0, 1)', adr('B3', 1)).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference).toEqual(CellAddress.relative(5, 13)) - }) - - it('OFFSET parsing into cell reference with negative column shift', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=OFFSET(C3, 0, -1)', adr('B2')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference).toEqual(CellAddress.relative(0, 1)) - }) - - it('OFFSET parsing into cell reference with some height', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=OFFSET(F16, 2, 0, 3)', adr('B3', 1)).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start).toEqual(CellAddress.relative(4, 15)) - expect(ast.end).toEqual(CellAddress.relative(4, 17)) - }) - - it('OFFSET parsing into cell reference with some width', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=OFFSET(F16, 0, 2, 1, 3)', adr('B3', 1)).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start).toEqual(CellAddress.relative(6, 13)) - expect(ast.end).toEqual(CellAddress.relative(8, 13)) - }) - - it('OFFSET parsing into cell range in different sheet', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enUS)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=OFFSET(Sheet2!F16, 0, 2, 1, 3)', adr('B3', 0)).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start).toEqual(CellAddress.relative(6, 13, 1)) - expect(ast.end).toEqual(CellAddress.relative(8, 13, 1)) - }) - - it('OFFSET first argument need to be reference', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(42, 0, 0)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('First argument to OFFSET is not a reference') - }) - - it('OFFSET second argument need to be static number', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, C3, 0)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Second argument to OFFSET is not a static number') - }) - - it('OFFSET second argument need to be integer', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 1.3, 0)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Second argument to OFFSET is not a static number') - }) - - it('OFFSET third argument need to be static number', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, C3)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Third argument to OFFSET is not a static number') - }) - - it('OFFSET third argument need to be integer', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, 1.3)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Third argument to OFFSET is not a static number') - }) - - it('OFFSET fourth argument need to be static number', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, 0, B3)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Fourth argument to OFFSET is not a static number') - }) - - it('OFFSET fourth argument need to be static number bigger than 0', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, 0, 0)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Fourth argument to OFFSET is too small number') - }) - - it('OFFSET fourth argument need to be integer', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, 0, 1.3)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Fourth argument to OFFSET is not integer') - }) - - it('OFFSET fifth argument need to be static number', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, 0, 1, B3)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Fifth argument to OFFSET is not a static number') - }) - - it('OFFSET fifth argument need to be static number bigger than 0', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, 0, 1, 0)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Fifth argument to OFFSET is too small number') - }) - - it('OFFSET fifth argument need to be integer', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=OFFSET(A1, 0, 0, 1, 1.3)', adr('A1')) - expect(errors[0].type).toBe('StaticOffsetError') - expect(errors[0].message).toBe('Fifth argument to OFFSET is not integer') - }) - - it('OFFSET resulting reference out of the sheet in top left row', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {ast, errors} = parser.parse('=OFFSET(A1, -1, 0)', adr('A1')) - expect(errors.length).toBe(0) - expect((ast as ErrorAst).error).toEqual(new CellError(ErrorType.REF, ErrorMessage.OutOfSheet)) - }) - - it('OFFSET resulting reference out of the sheet in top left column', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {ast, errors} = parser.parse('=OFFSET(A1, 0, -1)', adr('A1')) - expect(errors.length).toBe(0) - expect((ast as ErrorAst).error).toEqual(new CellError(ErrorType.REF, ErrorMessage.OutOfSheet)) - }) - - it('OFFSET case insensitive', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=oFfSeT(F16, 0, 0)', adr('B3', 1)).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference).toEqual(CellAddress.relative(4, 13)) - }) - - it('parser returns address with a sheet reference', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enUS)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=OFFSET(Sheet2!A1, 0, 0)', adr('A1', 0)).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference).toEqual(CellAddress.relative(0, 0, 1)) - }) - - it('function OFFSET can reference a different sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['sheet1']], - Sheet2: [['sheet2', '=OFFSET(Sheet1!A1, 0, 0)']], - }) - - expect(engine.getCellValue(adr('B1', engine.getSheetId('Sheet2')))).toEqual('sheet1') - }) -}) diff --git a/test/unit/parser/parser-caching.spec.ts b/test/unit/parser/parser-caching.spec.ts deleted file mode 100644 index 40310cd49d..0000000000 --- a/test/unit/parser/parser-caching.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Config} from '../../../src/Config' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('ParserWithCaching - caching', () => { - it('use cache for similar formulas', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast1 = parser.parse('=A1', adr('A1')).ast - const ast2 = parser.parse('=A2', adr('A2')).ast - - expect(ast1).toEqual(ast2) - expect(parser.statsCacheUsed).toBe(1) - }) - - it("doesn't count cache for different formulas", () => { - const parser = buildEmptyParserWithCaching(new Config()) - - parser.parse('=A1', adr('A1')).ast - parser.parse('=A2+A3', adr('A1')).ast - - expect(parser.statsCacheUsed).toBe(0) - }) -}) diff --git a/test/unit/parser/parser-dependencies.spec.ts b/test/unit/parser/parser-dependencies.spec.ts deleted file mode 100644 index 940c87d762..0000000000 --- a/test/unit/parser/parser-dependencies.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import {AbsoluteCellRange} from '../../../src/AbsoluteCellRange' -import {absolutizeDependencies} from '../../../src/absolutizeDependencies' -import {Config} from '../../../src/Config' -import {NamedExpressionDependency} from '../../../src/parser' -import {adr, expectArrayWithSameContent} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Parsing collecting dependencies', () => { - it('works for CELL_REFERENCE with relative dependency', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('B2') - - const parseResult = parser.parse('=B2', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - - expect(dependencies).toEqual([adr('B2')]) - }) - - it('works with absolute dependencies', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('B2') - - const parseResult = parser.parse('=$B$2', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - - expect(dependencies.length).toEqual(1) - expect(dependencies[0]).toEqual(adr('B2')) - }) - - it('works for CELL_RANGE', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('A1') - - const parseResult = parser.parse('=B2:C4', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - - expect(dependencies).toEqual([ - new AbsoluteCellRange(adr('B2'), adr('C4')), - ]) - }) - - it('works inside parenthesis', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('A1') - - const parseResult = parser.parse('=(A1+B2)', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - - expectArrayWithSameContent([adr('A1'), adr('B2')], dependencies) - }) - - it('goes inside unary minus', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('A1') - - const parseResult = parser.parse('=-B2', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - - expect(dependencies).toEqual([ - adr('B2'), - ]) - }) - - it('goes inside plus operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('A1') - - const parseResult = parser.parse('=B2+C3', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - - expect(dependencies).toEqual([ - adr('B2'), - adr('C3'), - ]) - }) - - it('goes inside function call arguments', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('A1') - - const parseResult = parser.parse('=SUM(B2, C3)', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - - expect(dependencies).toEqual([ - adr('B2'), - adr('C3'), - ]) - }) - - it('OFFSET call is correctly found as dependency', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('B2') - - const parseResult = parser.parse('=OFFSET(D4, 0, 0)', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - expect(dependencies).toEqual([ - adr('D4'), - ]) - }) - - it('COLUMNS arguments are not dependencies', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const formulaAddress = adr('B2') - - const parseResult = parser.parse('=COLUMNS(A1:B3)', formulaAddress) - const dependencies = absolutizeDependencies(parseResult.dependencies, formulaAddress) - expect(dependencies).toEqual([]) - }) - - it('works for named expression dependencies', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const parseResult = parser.parse('=FOO+bar', adr('A1')) - - const dependencies = absolutizeDependencies(parseResult.dependencies, adr('A1')) - - expect(dependencies).toEqual([ - new NamedExpressionDependency('FOO'), - new NamedExpressionDependency('bar'), - ]) - }) -}) diff --git a/test/unit/parser/parser.spec.ts b/test/unit/parser/parser.spec.ts deleted file mode 100644 index c49494d0eb..0000000000 --- a/test/unit/parser/parser.spec.ts +++ /dev/null @@ -1,986 +0,0 @@ -import {ErrorType, HyperFormula} from '../../../src' -import {CellError} from '../../../src' -import {Config} from '../../../src/Config' -import {SheetMapping} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB, plPL} from '../../../src/i18n/languages' -import {NoSheetWithNameError} from '../../../src/errors' -import { - AstNodeType, - buildCellErrorAst, - CellAddress, - CellRangeAst, - CellReferenceAst, - MinusOpAst, - MinusUnaryOpAst, - NamedExpressionAst, - NumberAst, - ParsingErrorType, - PlusOpAst, - PowerOpAst, - ProcedureAst, - StringAst, -} from '../../../src/parser' -import {columnIndexToLabel} from '../../../src/parser/addressRepresentationConverters' -import { - ArrayAst, - buildCellRangeAst, - buildCellReferenceAst, - buildColumnRangeAst, - buildErrorWithRawInputAst, - buildNumberAst, - buildRowRangeAst, - ColumnRangeAst, - ParenthesisAst, - RangeSheetReferenceType, RowRangeAst, -} from '../../../src/parser/Ast' -import {ColumnAddress} from '../../../src/parser/ColumnAddress' -import {RowAddress} from '../../../src/parser/RowAddress' -import {adr, unregisterAllLanguages} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('ParserWithCaching', () => { - beforeEach(() => { - unregisterAllLanguages() - HyperFormula.registerLanguage(plPL.langCode, plPL) - HyperFormula.registerLanguage(enGB.langCode, enGB) - }) - - it('integer literal', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=42', adr('A1')).ast - expect(ast).toEqual(buildNumberAst(42)) - }) - - it('negative integer literal', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=-42', adr('A1')).ast as MinusUnaryOpAst - expect(ast.type).toBe(AstNodeType.MINUS_UNARY_OP) - expect(ast.value).toEqual(buildNumberAst(42)) - }) - - it('string literal', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('="foobar"', adr('A1')).ast as StringAst - expect(ast.type).toBe(AstNodeType.STRING) - expect(ast.value).toBe('foobar') - }) - - it('plus operator on different nodes', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1+A5', adr('A1')).ast as PlusOpAst - expect(ast.type).toBe(AstNodeType.PLUS_OP) - expect(ast.left.type).toBe(AstNodeType.NUMBER) - expect(ast.right.type).toBe(AstNodeType.CELL_REFERENCE) - }) - - it('minus operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1-3', adr('A1')).ast as MinusOpAst - expect(ast.type).toBe(AstNodeType.MINUS_OP) - expect(ast.left.type).toBe(AstNodeType.NUMBER) - expect(ast.right.type).toBe(AstNodeType.NUMBER) - }) - - it('power operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=2^3', adr('A1')).ast as PowerOpAst - expect(ast.type).toBe(AstNodeType.POWER_OP) - expect(ast.left.type).toBe(AstNodeType.NUMBER) - expect(ast.right.type).toBe(AstNodeType.NUMBER) - }) - - it('power operator order', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=2*2^3', adr('A1')).ast as PowerOpAst - expect(ast.type).toBe(AstNodeType.TIMES_OP) - expect(ast.left.type).toBe(AstNodeType.NUMBER) - expect(ast.right.type).toBe(AstNodeType.POWER_OP) - }) - - it('joining nodes without braces', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=1 + 2 + 3', adr('A1')).ast as PlusOpAst - expect(ast.type).toBe(AstNodeType.PLUS_OP) - expect(ast.left.type).toBe(AstNodeType.PLUS_OP) - expect(ast.right.type).toBe(AstNodeType.NUMBER) - }) - - it('joining nodes with braces', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=1 + (2 + 3)', adr('A1')).ast as PlusOpAst - expect(ast.type).toBe(AstNodeType.PLUS_OP) - expect(ast.left.type).toBe(AstNodeType.NUMBER) - - const right = ast.right as ParenthesisAst - expect(right.type).toBe(AstNodeType.PARENTHESIS) - expect(right.expression.type).toBe(AstNodeType.PLUS_OP) - }) - - it('float literal', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=3.14', adr('A1')).ast - expect(ast).toEqual(buildNumberAst(3.14)) - }) - - it('float literal with different decimal separator', () => { - const parser = buildEmptyParserWithCaching(new Config({ - decimalSeparator: ',', - functionArgSeparator: ';' - }), new SheetMapping(buildTranslationPackage(enGB))) - const ast1 = parser.parse('=3,14', adr('A1')).ast - const ast2 = parser.parse('=03,14', adr('A1')).ast - const ast3 = parser.parse('=,14', adr('A1')).ast - - expect(ast1).toEqual(buildNumberAst(3.14)) - expect(ast2).toEqual(buildNumberAst(3.14)) - expect(ast3).toEqual(buildNumberAst(0.14)) - }) - - it('leading zeros of number literals', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const int = parser.parse('=01234', adr('A1')).ast as NumberAst - const float = parser.parse('=03.14', adr('A1')).ast as NumberAst - expect(int.type).toBe(AstNodeType.NUMBER) - expect(int.value).toBe(1234) - expect(float.type).toBe(AstNodeType.NUMBER) - expect(float.value).toBe(3.14) - }) - - it('allow to accept different lexer configs', () => { - const parser1 = buildEmptyParserWithCaching(new Config()) - const parser2 = buildEmptyParserWithCaching(new Config({functionArgSeparator: ';'}), new SheetMapping(buildTranslationPackage(enGB))) - - const ast1 = parser1.parse('=SUM(1, 2)', adr('A1')).ast as ProcedureAst - const ast2 = parser2.parse('=SUM(1; 2)', adr('A1')).ast as ProcedureAst - - expect(ast1.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast2.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast1).toEqual(ast2) - }) - - it('with default config should return error for non-breakable space', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const { ast, errors } = parser.parse('=\u00A042', adr('A1')) - - expect(ast.type).toBe(AstNodeType.ERROR) - expect(errors[0].type).toBe(ParsingErrorType.LexingError) - }) - - it('when set ignoreWhiteSpace = \'any\' should accept a non-breakable space', () => { - const parser = buildEmptyParserWithCaching(new Config({ ignoreWhiteSpace: 'any' })) - - const { ast } = parser.parse('=\u00A042', adr('A1')) - - expect(ast.type).toEqual(AstNodeType.NUMBER) - expect(ast.leadingWhitespace).toEqual('\u00A0') - }) - - it('error literal', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=#REF!', adr('A1')).ast - expect(ast).toEqual(buildCellErrorAst(new CellError(ErrorType.REF))) - }) - - it('error literals are case insensitive', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=#rEf!', adr('A1')).ast - expect(ast).toEqual(buildCellErrorAst(new CellError(ErrorType.REF))) - }) - - it('reference to address in nonexisting sheet returns cell reference ast', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const ast = parser.parse('=Sheet2!A1', adr('A1')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.relative(0, 0, 1))) - }) -}) - -describe('Functions', () => { - beforeEach(() => { - unregisterAllLanguages() - HyperFormula.registerLanguage(plPL.langCode, plPL) - HyperFormula.registerLanguage(enGB.langCode, enGB) - }) - - it('SUM function without args', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=SUM()', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toBe('SUM') - expect(ast.args.length).toBe(0) - }) - - it('SUM function with args', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=SUM(1, A1)', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toBe('SUM') - expect(ast.args[0].type).toBe(AstNodeType.NUMBER) - expect(ast.args[1].type).toBe(AstNodeType.CELL_REFERENCE) - }) - - it('SUM function with expression arg', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=SUM(1 / 2 + SUM(1,2))', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.args.length).toBe(1) - expect(ast.args[0].type).toBe(AstNodeType.PLUS_OP) - - const arg = ast.args[0] as PlusOpAst - expect(arg.left.type).toBe(AstNodeType.DIV_OP) - expect(arg.right.type).toBe(AstNodeType.FUNCTION_CALL) - }) - - it('function without polish characters', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=żółćąęźśńŻÓŁĆĄĘŹŚŃ()', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toBe('ŻÓŁĆĄĘŹŚŃŻÓŁĆĄĘŹŚŃ') - expect(ast.args.length).toBe(0) - }) - - it('function with dot separator', () => { - const parser = buildEmptyParserWithCaching(new Config({language: 'plPL'}), new SheetMapping(buildTranslationPackage(plPL))) - const ast = parser.parse('=NR.SER.OST.DN.MIEŚ()', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toBe('EOMONTH') - expect(ast.args.length).toBe(0) - }) - - it('function name should be translated during parsing', () => { - const parser = buildEmptyParserWithCaching(new Config({language: 'plPL'}), new SheetMapping(buildTranslationPackage(plPL))) - const ast = parser.parse('=SUMA()', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toBe('SUM') - expect(ast.args.length).toBe(0) - }) - - it('function with number', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=DEC2BIN(4)', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toEqual('DEC2BIN') - }) - - it('should leave original name if procedure translation not known', () => { - const parser = buildEmptyParserWithCaching(new Config({language: 'plPL'}), new SheetMapping(buildTranslationPackage(plPL))) - const ast = parser.parse('=FOOBAR()', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toBe('FOOBAR') - expect(ast.args.length).toBe(0) - }) - - it('should be case insensitive', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const ast = parser.parse('=sum(1)', adr('A1')).ast as ProcedureAst - expect(ast.type).toBe(AstNodeType.FUNCTION_CALL) - expect(ast.procedureName).toBe('SUM') - }) - - it('should be a valid function name', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - expect((parser.parse('=A()', adr('A1')).ast as ProcedureAst).procedureName).toEqual('A') - expect((parser.parse('=AA()', adr('A1')).ast as ProcedureAst).procedureName).toEqual('AA') - expect((parser.parse('=A.B()', adr('A1')).ast as ProcedureAst).procedureName).toEqual('A.B') - expect((parser.parse('=A.B.C()', adr('A1')).ast as ProcedureAst).procedureName).toEqual('A.B.C') - expect((parser.parse('=A_B()', adr('A1')).ast as ProcedureAst).procedureName).toEqual('A_B') - expect((parser.parse('=A42()', adr('A1')).ast as ProcedureAst).procedureName).toEqual('A42') - }) -}) - -describe('cell references and ranges', () => { - it('absolute cell reference', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=$B$3', adr('B2')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.absolute(1, 2))) - }) - - it('relative cell reference', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=B3', adr('B2')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.relative(0, 1))) - }) - - it('absolute column cell reference', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=$B3', adr('B2')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.absoluteCol(1, 1))) - }) - - it('absolute row cell reference', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=B$3', adr('B2')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.absoluteRow(0, 2))) - }) - - it('cell references should not be case sensitive', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=d1', adr('A1')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.relative(3, 0))) - }) - - it('cell reference by default has sheet from the sheet it is written', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=D1', adr('A1', 1)).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.relative(3, 0))) - }) - - it('cell reference with sheet name', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=Sheet2!D1', adr('A1')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.relative(3, 0, 1))) - }) - - it('attempting to fetch an unknown sheet throws error', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - - const sheetName = 'Sheet3' - - expect(() => { - sheetMapping.getSheetIdOrThrowError('Sheet3') - }).toThrow(new NoSheetWithNameError(sheetName)) - }) - - it('using unknown sheet gives cell reference ast', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=Sheet2!A1', adr('A1')).ast - - expect(ast).toEqual(buildCellReferenceAst(CellAddress.relative(0, 0, 0))) - }) - - it('sheet name with other characters', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet_zażółć_gęślą_jaźń') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=Sheet_zażółć_gęślą_jaźń!A1', adr('A1')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference.sheet).toBe(1) - }) - - it('sheet name is case insensitive', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=shEEt2!A1', adr('A1')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference.sheet).toBe(1) - }) - - it('sheet name with spaces', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet with spaces') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse("='Sheet with spaces'!A1", adr('A1')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference.sheet).toBe(1) - }) - - it('sheet name inside quotes', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse("='Sheet2'!A1", adr('A1')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference.sheet).toBe(1) - }) - - it('sheet name inside quotes with special characters', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('~`!@#$%^&*()_-+_=/|?{}[]\"') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse("='~`!@#$%^&*()_-+_=/|?{}[]\"'!A2", adr('A1')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference.sheet).toBe(1) - }) - - it('sheet name inside quotes with escaped quote', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet("Name'with'quotes") - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse("='Name''with''quotes'!A1", adr('A1')).ast as CellReferenceAst - expect(ast.type).toBe(AstNodeType.CELL_REFERENCE) - expect(ast.reference.sheet).toBe(1) - }) - - it('simple cell range', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=A1:B2', adr('A1')).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - }) - - it('cell range with both start and end sheets specified', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=Sheet2!A1:Sheet2!B2', adr('A1')).ast as CellRangeAst - - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start.sheet).toEqual(1) - expect(ast.end.sheet).toEqual(1) - }) - - it('cell range may have only sheet specified in start address but end of range is also absolute', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=Sheet2!A1:B2', adr('A1')).ast as CellRangeAst - - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start.sheet).toEqual(1) - expect(ast.end.sheet).toEqual(1) - }) - - it('cell range with absolute sheet only on end side is a parsing error', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const {errors} = parser.parse('=A1:Sheet2!B2', adr('A1')) - - expect(errors[0].type).toBe(ParsingErrorType.ParserError) - }) - - it('cell range with different start and end sheets', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - sheetMapping.addSheet('Sheet3') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=Sheet2!A1:Sheet3!B2', adr('A1')).ast as CellRangeAst - - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start.sheet).toEqual(1) - expect(ast.end.sheet).toEqual(2) - }) - - it('offset has relative sheet reference', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const ast = parser.parse('=OFFSET(A1, 1, 2)', adr('A1')).ast as CellReferenceAst - - expect(ast.reference.sheet).toBe(undefined) - }) - - it('cell range with nonexsiting start sheet should return cell range ast', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=Sheet3!A1:Sheet2!B2', adr('A1')).ast - - expect(ast).toEqual(buildCellRangeAst(CellAddress.relative(0, 0, 1), CellAddress.relative(1, 1, 2), RangeSheetReferenceType.BOTH_ABSOLUTE)) - }) - - it('cell range with nonexsiting end sheet should return cell range ast', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - const ast = parser.parse('=Sheet2!A1:Sheet3!B2', adr('A1')).ast - - expect(ast).toEqual(buildCellRangeAst(CellAddress.relative(0, 0, 1), CellAddress.relative(1, 1, 2), RangeSheetReferenceType.BOTH_ABSOLUTE)) - }) - - it('cell reference beyond maximum row limit is #NAME', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const maxRow = Config.defaultConfig.maxRows - - const maxRowAst = parser.parse(`=A${maxRow}`, adr('A1')).ast as CellReferenceAst - const maxRowPlusOneAst = parser.parse(`=A${maxRow + 1}`, adr('A1')).ast - - expect(maxRowAst.type).toEqual(AstNodeType.CELL_REFERENCE) - expect(maxRowAst.reference.row).toEqual(maxRow - 1) - expect(maxRowPlusOneAst).toEqual(buildErrorWithRawInputAst(`A${maxRow + 1}`, new CellError(ErrorType.NAME))) - }) - - it('cell reference beyond maximum column limit is #NAME', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const maxColumns = Config.defaultConfig.maxColumns - - const maxColumnAst = parser.parse(`=${columnIndexToLabel(maxColumns - 1)}1`, adr('A1')).ast as CellReferenceAst - const maxColumnPlusOneAst = parser.parse(`=${columnIndexToLabel(maxColumns)}1`, adr('A1')).ast - - expect(maxColumnAst.type).toEqual(AstNodeType.CELL_REFERENCE) - expect(maxColumnAst.reference.col).toEqual(maxColumns - 1) - expect(maxColumnPlusOneAst).toEqual(buildErrorWithRawInputAst(`${columnIndexToLabel(maxColumns)}1`, new CellError(ErrorType.NAME))) - }) - - it('cell range start beyond maximum column/row limit is #NAME', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const maxRow = Config.defaultConfig.maxRows - const maxColumns = Config.defaultConfig.maxColumns - - const ast1 = parser.parse(`=A${maxRow + 1}:B2`, adr('A1')).ast - const ast2 = parser.parse(`=${columnIndexToLabel(maxColumns)}1:B2`, adr('A1')).ast - - expect(ast1).toEqual(buildErrorWithRawInputAst(`A${maxRow + 1}:B2`, new CellError(ErrorType.NAME))) - expect(ast2).toEqual(buildErrorWithRawInputAst(`${columnIndexToLabel(maxColumns)}1:B2`, new CellError(ErrorType.NAME))) - }) - - it('cell range end beyond maximum column/row limit is #NAME', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const maxRow = Config.defaultConfig.maxRows - const maxColumns = Config.defaultConfig.maxColumns - - const ast1 = parser.parse(`=A1:B${maxRow + 1}`, adr('A1')).ast - const ast2 = parser.parse(`=A1:${columnIndexToLabel(maxColumns)}1`, adr('A1')).ast - - expect(ast1).toEqual(buildErrorWithRawInputAst(`A1:B${maxRow + 1}`, new CellError(ErrorType.NAME))) - expect(ast2).toEqual(buildErrorWithRawInputAst(`A1:${columnIndexToLabel(maxColumns)}1`, new CellError(ErrorType.NAME))) - }) - - describe('reversed range', () => { - it('relative', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const notReversedAst = parser.parse('=A1:B2', adr('A1')).ast as CellRangeAst - - ['=B2:A1', '=B1:A2', '=A2:B1'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - }) - - it('with absolute addressing', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - let notReversedAst = parser.parse('=$A1:B2', adr('A1')).ast as CellRangeAst - ['=$A2:B1', '=B1:$A2', '=B2:$A1'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - - notReversedAst = parser.parse('=A$1:B2', adr('A1')).ast as CellRangeAst - ['=A2:B$1', '=B$1:A2', '=B2:A$1'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - - notReversedAst = parser.parse('=A1:$B2', adr('A1')).ast as CellRangeAst - ['=A2:$B1', '=$B1:A2', '=$B2:A1'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - - notReversedAst = parser.parse('=A1:B$2', adr('A1')).ast as CellRangeAst - ['=A$2:B1', '=B1:A$2', '=B$2:A1'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - - notReversedAst = parser.parse('=$A$1:B2', adr('A1')).ast as CellRangeAst - ['=$A2:B$1', '=B$1:$A2', '=B2:$A$1'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - - notReversedAst = parser.parse('=$A1:B$2', adr('A1')).ast as CellRangeAst - ['=$A$2:B1', '=B1:$A$2', '=B$2:$A1'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - }) - - it('with sheets specified', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet0') - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - let ast = parser.parse('=Sheet1!B2:A1', adr('A1')).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start.sheet).toEqual(1) - expect(ast.end.sheet).toEqual(1) - - const res = parser.parse('=B2:Sheet1!A1', adr('A1')) - expect(res.errors[0].type).toBe(ParsingErrorType.ParserError) - - ast = parser.parse('=Sheet1!B2:Sheet1!A1', adr('A1')).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start.sheet).toEqual(1) - expect(ast.end.sheet).toEqual(1) - - ast = parser.parse('=Sheet1!B2:Sheet2!A1', adr('A1')).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start.sheet).toEqual(1) - expect(ast.end.sheet).toEqual(2) - - ast = parser.parse('=Sheet2!B2:Sheet1!A1', adr('A1')).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast.start.sheet).toEqual(1) - expect(ast.end.sheet).toEqual(2) - }) - - it('with OFFSET', () => { - const parser = buildEmptyParserWithCaching(new Config()) - const notReversedAst = parser.parse('=A1:B2', adr('A1')).ast as CellRangeAst - - ['=B2:OFFSET(A1, 0, 0)', '=OFFSET(B2, 0, 0):A1', '=OFFSET(B2, 0, 0):OFFSET(A1, 0, 0)', '=OFFSET(A2, 0, 0):OFFSET(B1, 0, 0)'].forEach(formula => { - const ast = parser.parse(formula, adr('A1')).ast as CellRangeAst - expect(ast).toEqual(notReversedAst) - }) - }) - }) -}) - -describe('Column ranges', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - it('column range', () => { - const ast = parser.parse('=C:D', adr('A1')).ast - expect(ast).toEqual(buildColumnRangeAst(ColumnAddress.relative(2), ColumnAddress.relative(3), RangeSheetReferenceType.RELATIVE)) - }) - - it('column range with sheet absolute', () => { - const ast = parser.parse('=Sheet1!C:D', adr('A1')).ast - expect(ast).toEqual(buildColumnRangeAst(ColumnAddress.relative(2, 0), ColumnAddress.relative(3, 0), RangeSheetReferenceType.START_ABSOLUTE)) - }) - - it('column range with both sheets absolute - same sheet', () => { - const ast = parser.parse('=Sheet1!C:Sheet1!D', adr('A1')).ast - expect(ast).toEqual(buildColumnRangeAst(ColumnAddress.relative(2, 0), ColumnAddress.relative(3, 0), RangeSheetReferenceType.BOTH_ABSOLUTE)) - }) - - it('column range with both sheets absolute - different sheet', () => { - const ast = parser.parse('=Sheet1!C:Sheet2!D', adr('A1')).ast - expect(ast).toEqual(buildColumnRangeAst(ColumnAddress.relative(2, 0), ColumnAddress.relative(3, 1), RangeSheetReferenceType.BOTH_ABSOLUTE)) - }) - - it('column range with absolute column address', () => { - const ast = parser.parse('=$C:D', adr('A1')).ast - expect(ast).toEqual(buildColumnRangeAst(ColumnAddress.absolute(2), ColumnAddress.relative(3), RangeSheetReferenceType.RELATIVE)) - }) - - it('column range with absolute sheet only on end side is a parsing error', () => { - const {errors} = parser.parse('=A:Sheet2!B', adr('A1')) - expect(errors[0].type).toBe(ParsingErrorType.ParserError) - }) - - it('column range beyond size limits is #NAME', () => { - const maxColumns = Config.defaultConfig.maxColumns - const ast1 = parser.parse(`=A:${columnIndexToLabel(maxColumns - 1)}`, adr('A1')).ast as ColumnRangeAst - const ast2 = parser.parse(`=A:${columnIndexToLabel(maxColumns)}`, adr('A1')).ast - const ast3 = parser.parse(`=${columnIndexToLabel(maxColumns)}:B`, adr('A1')).ast - - expect(ast1.type).toEqual(AstNodeType.COLUMN_RANGE) - expect(ast2).toEqual(buildErrorWithRawInputAst(`A:${columnIndexToLabel(maxColumns)}`, new CellError(ErrorType.NAME))) - expect(ast3).toEqual(buildErrorWithRawInputAst(`${columnIndexToLabel(maxColumns)}:B`, new CellError(ErrorType.NAME))) - }) - - it('reversed column range', () => { - let notReversedAst = parser.parse('=A:B', adr('A1')).ast - let reversedAst = parser.parse('=B:A', adr('A1')).ast - expect(reversedAst).toEqual(notReversedAst) - - notReversedAst = parser.parse('=$A:B', adr('A1')).ast - reversedAst = parser.parse('=B:$A', adr('A1')).ast - expect(reversedAst).toEqual(notReversedAst) - - notReversedAst = parser.parse('=A:$B', adr('A1')).ast - reversedAst = parser.parse('=$B:A', adr('A1')).ast - expect(reversedAst).toEqual(notReversedAst) - - reversedAst = parser.parse('=Sheet1!B:A', adr('A1')).ast as ColumnRangeAst - expect(reversedAst.type).toEqual(AstNodeType.COLUMN_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(0) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.START_ABSOLUTE) - - const res = parser.parse('=B:Sheet1!A', adr('A1')) - expect(res.errors[0].type).toBe(ParsingErrorType.ParserError) - - reversedAst = parser.parse('=Sheet1!B:Sheet2!A', adr('A1')).ast as ColumnRangeAst - expect(reversedAst.type).toEqual(AstNodeType.COLUMN_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(1) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.BOTH_ABSOLUTE) - - reversedAst = parser.parse('=Sheet1!B:Sheet1!A', adr('A1')).ast as ColumnRangeAst - expect(reversedAst.type).toEqual(AstNodeType.COLUMN_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(0) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.BOTH_ABSOLUTE) - - reversedAst = parser.parse('=Sheet2!B:Sheet1!A', adr('A1')).ast as ColumnRangeAst - expect(reversedAst.type).toEqual(AstNodeType.COLUMN_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(1) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.BOTH_ABSOLUTE) - }) -}) - -describe('Row ranges', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - - it('row range', () => { - const ast = parser.parse('=3:4', adr('A1')).ast - expect(ast).toEqual(buildRowRangeAst(RowAddress.relative(2), RowAddress.relative(3), RangeSheetReferenceType.RELATIVE)) - }) - - it('row range with sheet absolute', () => { - const ast = parser.parse('=Sheet1!3:4', adr('A1')).ast - expect(ast).toEqual(buildRowRangeAst(RowAddress.relative(2, 0), RowAddress.relative(3, 0), RangeSheetReferenceType.START_ABSOLUTE)) - }) - - it('row range with both sheets absolute - same sheet', () => { - const ast = parser.parse('=Sheet1!3:Sheet1!4', adr('A1')).ast - expect(ast).toEqual(buildRowRangeAst(RowAddress.relative(2, 0), RowAddress.relative(3, 0), RangeSheetReferenceType.BOTH_ABSOLUTE)) - }) - - it('row range with both sheets absolute - different sheet', () => { - const ast = parser.parse('=Sheet1!3:Sheet2!4', adr('A1')).ast - expect(ast).toEqual(buildRowRangeAst(RowAddress.relative(2, 0), RowAddress.relative(3, 1), RangeSheetReferenceType.BOTH_ABSOLUTE)) - }) - - it('row range with absolute row address', () => { - const ast = parser.parse('=$3:4', adr('A1')).ast - expect(ast).toEqual(buildRowRangeAst(RowAddress.absolute(2), RowAddress.relative(3), RangeSheetReferenceType.RELATIVE)) - }) - - it('row range with absolute sheet only on end side is a parsing error', () => { - const {errors} = parser.parse('=1:Sheet2!2', adr('A1')) - expect(errors[0].type).toBe(ParsingErrorType.ParserError) - }) - - it('reversed row range', () => { - let notReversedAst = parser.parse('=1:2', adr('A1')).ast - let reversedAst = parser.parse('=2:1', adr('A1')).ast - expect(reversedAst).toEqual(notReversedAst) - - notReversedAst = parser.parse('=$1:2', adr('A1')).ast - reversedAst = parser.parse('=2:$1', adr('A1')).ast - expect(reversedAst).toEqual(notReversedAst) - - notReversedAst = parser.parse('=1:$2', adr('A1')).ast - reversedAst = parser.parse('=$2:1', adr('A1')).ast - expect(reversedAst).toEqual(notReversedAst) - - reversedAst = parser.parse('=Sheet1!2:1', adr('A1')).ast as RowRangeAst - expect(reversedAst.type).toEqual(AstNodeType.ROW_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(0) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.START_ABSOLUTE) - - const res = parser.parse('=2:Sheet1!1', adr('A1')) - expect(res.errors[0].type).toBe(ParsingErrorType.ParserError) - - reversedAst = parser.parse('=Sheet1!2:Sheet2!1', adr('A1')).ast as RowRangeAst - expect(reversedAst.type).toEqual(AstNodeType.ROW_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(1) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.BOTH_ABSOLUTE) - - reversedAst = parser.parse('=Sheet1!2:Sheet1!1', adr('A1')).ast as RowRangeAst - expect(reversedAst.type).toEqual(AstNodeType.ROW_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(0) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.BOTH_ABSOLUTE) - - reversedAst = parser.parse('=Sheet2!2:Sheet1!1', adr('A1')).ast as RowRangeAst - expect(reversedAst.type).toEqual(AstNodeType.ROW_RANGE) - expect(reversedAst.start.sheet).toEqual(0) - expect(reversedAst.end.sheet).toEqual(1) - expect(reversedAst.sheetReferenceType).toEqual(RangeSheetReferenceType.BOTH_ABSOLUTE) - }) -}) - -describe('Named expressions', () => { - it('should be a valid name for named expression', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - expect((parser.parse('=_A', adr('A1')).ast as NamedExpressionAst).expressionName).toEqual('_A') - expect((parser.parse('=A', adr('A1')).ast as NamedExpressionAst).expressionName).toEqual('A') - expect((parser.parse('=Aa', adr('A1')).ast as NamedExpressionAst).expressionName).toEqual('Aa') - expect((parser.parse('=B.', adr('A1')).ast as NamedExpressionAst).expressionName).toEqual('B.') - expect((parser.parse('=foo_bar', adr('A1')).ast as NamedExpressionAst).expressionName).toEqual('foo_bar') - expect((parser.parse('=A...', adr('A1')).ast as NamedExpressionAst).expressionName).toEqual('A...') - expect((parser.parse('=B___', adr('A1')).ast as NamedExpressionAst).expressionName).toEqual('B___') - }) - - it('named expression ast with leading whitespace', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('= true', adr('A1')).ast as NamedExpressionAst - - expect(ast.type).toBe(AstNodeType.NAMED_EXPRESSION) - expect(ast.expressionName).toBe('true') - expect(ast.leadingWhitespace).toBe(' ') - }) -}) - -describe('Matrices', () => { - it('simplest matrix', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('={1}', adr('A1')).ast as ArrayAst - expect(ast.type).toBe(AstNodeType.ARRAY) - expect(ast.args.length).toEqual(1) - expect(ast.args[0].length).toEqual(1) - }) - - it('row matrix', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('={1,2,3}', adr('A1')).ast as ArrayAst - expect(ast.type).toBe(AstNodeType.ARRAY) - expect(ast.args.length).toEqual(1) - expect(ast.args[0].length).toEqual(3) - }) - - it('column matrix', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('={1;2;3}', adr('A1')).ast as ArrayAst - expect(ast.type).toBe(AstNodeType.ARRAY) - expect(ast.args.length).toEqual(3) - expect(ast.args[0].length).toEqual(1) - expect(ast.args[1].length).toEqual(1) - expect(ast.args[2].length).toEqual(1) - }) - - it('square matrix', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('={1,2,3;4,5,6;7,8,9}', adr('A1')).ast as ArrayAst - expect(ast.type).toBe(AstNodeType.ARRAY) - expect(ast.args.length).toEqual(3) - expect(ast.args[0].length).toEqual(3) - expect(ast.args[1].length).toEqual(3) - expect(ast.args[2].length).toEqual(3) - }) - - it('longer matrix with extras', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('={SUM(1, 2, 3), 2, {1,2,3}}', adr('A1')).ast as ArrayAst - expect(ast.type).toBe(AstNodeType.ARRAY) - expect(ast.args.length).toEqual(1) - expect(ast.args[0].length).toEqual(3) - const ast2 = ast.args[0][2] as ArrayAst - expect(ast2.type).toBe(AstNodeType.ARRAY) - expect(ast2.args.length).toEqual(1) - expect(ast2.args[0].length).toEqual(3) - }) - - it('matrix in other expressions', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1+{1,2,3}', adr('A1')).ast as PlusOpAst - const ast2 = ast.right as ArrayAst - expect(ast2.type).toBe(AstNodeType.ARRAY) - expect(ast2.args.length).toEqual(1) - expect(ast2.args[0].length).toEqual(3) - }) - - it('square matrix, other separators', () => { - const parser = buildEmptyParserWithCaching(new Config({arrayRowSeparator: '|', arrayColumnSeparator: ';'})) - - const ast = parser.parse('={1;2;3|4;5;6|7;8;9}', adr('A1')).ast as ArrayAst - expect(ast.type).toBe(AstNodeType.ARRAY) - expect(ast.args.length).toEqual(3) - expect(ast.args[0].length).toEqual(3) - expect(ast.args[1].length).toEqual(3) - expect(ast.args[2].length).toEqual(3) - }) -}) - -describe('Parsing errors', () => { - it('errors - lexing errors', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const input = ["='foo'", "=foo'bar", "=''''''", '=@'] - - input.forEach((formula) => { - const {ast, errors} = parser.parse(formula, adr('A1')) - expect(ast.type).toBe(AstNodeType.ERROR) - expect(errors[0].type).toBe(ParsingErrorType.LexingError) - }) - }) - - it('parsing error - not all input parsed', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors} = parser.parse('=1A1', adr('A1')) - expect(errors[0].type).toBe(ParsingErrorType.ParserError) - }) - - it('unknown error literal', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {ast, errors} = parser.parse('=#FOO!', adr('A1')) - expect(ast.type).toBe(AstNodeType.ERROR) - expect(errors[0].type).toBe(ParsingErrorType.ParserError) - }) -}) diff --git a/test/unit/parser/percent-operator.spec.ts b/test/unit/parser/percent-operator.spec.ts deleted file mode 100644 index 1492bd6b72..0000000000 --- a/test/unit/parser/percent-operator.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import {Config} from '../../../src/Config' -import {AstNodeType, MinusUnaryOpAst, PlusOpAst, PlusUnaryOpAst} from '../../../src/parser' -import {PercentOpAst, TimesOpAst} from '../../../src/parser/Ast' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('percent', () => { - it('should parse % as operator', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1%', adr('A1')).ast as PercentOpAst - expect(ast.type).toBe(AstNodeType.PERCENT_OP) - expect(ast.value.type).toBe(AstNodeType.NUMBER) - }) - - it('% over unary minus', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=-1%', adr('A1')).ast as MinusUnaryOpAst - expect(ast.type).toBe(AstNodeType.MINUS_UNARY_OP) - expect(ast.value.type).toBe(AstNodeType.PERCENT_OP) - }) - - it('% over unary plus', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=+1%', adr('A1')).ast as PlusUnaryOpAst - expect(ast.type).toBe(AstNodeType.PLUS_UNARY_OP) - expect(ast.value.type).toBe(AstNodeType.PERCENT_OP) - }) - - it('% over addition op', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=42+1%', adr('A1')).ast as PlusOpAst - expect(ast.type).toBe(AstNodeType.PLUS_OP) - expect(ast.right.type).toBe(AstNodeType.PERCENT_OP) - }) - - it('% over multiplication op', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=42*1%', adr('A1')).ast as TimesOpAst - expect(ast.type).toBe(AstNodeType.TIMES_OP) - expect(ast.right.type).toBe(AstNodeType.PERCENT_OP) - }) - - it('% on the left', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=1%+42', adr('A1')).ast as PlusOpAst - expect(ast.type).toBe(AstNodeType.PLUS_OP) - expect(ast.left.type).toBe(AstNodeType.PERCENT_OP) - }) - - it('% after procedure', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=SUM(1,2)%', adr('A1')).ast as PercentOpAst - expect(ast.type).toBe(AstNodeType.PERCENT_OP) - expect(ast.value.type).toBe(AstNodeType.FUNCTION_CALL) - }) - - it('%% should not parse', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=100%%', adr('A1')).ast as PercentOpAst - expect(ast.type).toBe(AstNodeType.ERROR) - }) -}) diff --git a/test/unit/parser/range-offset.spec.ts b/test/unit/parser/range-offset.spec.ts deleted file mode 100644 index 859c48154d..0000000000 --- a/test/unit/parser/range-offset.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import {Config} from '../../../src/Config' -import {SheetMapping} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB} from '../../../src/i18n/languages' -import {AstNodeType, CellRangeAst, ParsingErrorType} from '../../../src/parser' -import {RangeSheetReferenceType} from '../../../src/parser/Ast' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Parser - range offset', () => { - it('OFFSET - usage with range', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const ast = parser.parse('=A1:OFFSET(A1, 1, 1, 1, 1)', adr('A1')).ast as CellRangeAst - const ast2 = parser.parse('=OFFSET(A1, 1, 1, 1, 1):OFFSET(B2, 1, 1, 1, 1)', adr('A1')).ast as CellRangeAst - const ast3 = parser.parse('=OFFSET(A1, 1, 1, 1, 1):B3', adr('A1')).ast as CellRangeAst - expect(ast.type).toBe(AstNodeType.CELL_RANGE) - expect(ast2.type).toBe(AstNodeType.CELL_RANGE) - expect(ast3.type).toBe(AstNodeType.CELL_RANGE) - }) - - it('OFFSET - range offset not allowed', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const {errors: errors1} = parser.parse('=A1:OFFSET(B2, 0, 0, 2, 2)', adr('A1')) - const {errors: errors2} = parser.parse('=OFFSET(A1,0,0,2,2):A2', adr('A1')) - - expect(errors1[0].type).toBe(ParsingErrorType.RangeOffsetNotAllowed) - expect(errors2[0].type).toBe(ParsingErrorType.RangeOffsetNotAllowed) - }) - - it('OFFSET - sheet reference in range with offset start is ABSOLUTE', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const ast = parser.parse('=OFFSET(A1,0,0):OFFSET(B2,0,0)', adr('A1')).ast as CellRangeAst - - expect(ast.type).toEqual(AstNodeType.CELL_RANGE) - expect(ast.sheetReferenceType).toEqual(RangeSheetReferenceType.RELATIVE) - }) - - it('OFFSET - sheet reference in range with absolute start is START_ABSOLUTE', () => { - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(new Config(), sheetMapping) - const ast = parser.parse('=Sheet1!A1:OFFSET(B2, 0, 0)', adr('A1')).ast as CellRangeAst - - expect(ast.type).toEqual(AstNodeType.CELL_RANGE) - expect(ast.sheetReferenceType).toEqual(RangeSheetReferenceType.START_ABSOLUTE) - }) -}) diff --git a/test/unit/parser/unparse.spec.ts b/test/unit/parser/unparse.spec.ts deleted file mode 100644 index 60ec677362..0000000000 --- a/test/unit/parser/unparse.spec.ts +++ /dev/null @@ -1,612 +0,0 @@ -import {HyperFormula} from '../../../src' -import {Config} from '../../../src/Config' -import {SheetMapping} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB, plPL} from '../../../src/i18n/languages' -import {NamedExpressions} from '../../../src/NamedExpressions' -import {AstNodeType, Unparser} from '../../../src/parser' -import {adr, unregisterAllLanguages} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('Unparse', () => { - const config = new Config({ maxRows: 10 }) - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - sheetMapping.addSheet('Sheet with spaces') - sheetMapping.addSheet("Sheet'With'Quotes") - const parser = buildEmptyParserWithCaching(config, sheetMapping) - const namedExpressions = new NamedExpressions() - const unparser = new Unparser(config, sheetMapping, namedExpressions) - - beforeEach(() => { - unregisterAllLanguages() - HyperFormula.registerLanguage(plPL.langCode, plPL) - HyperFormula.registerLanguage(enGB.langCode, enGB) - }) - - it('#unparse', () => { - const formula = '=1+SUM(1, 2, 3)*3' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - expect(unparsed).toEqual(formula) - }) - - it('#unparse simple addreess', () => { - const formula = '=A1' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse simple addreess from other sheet', () => { - const formula = '=Sheet1!A1' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse absolute col', () => { - const formula = '=$A1' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse absolute row addreess', () => { - const formula = '=A$1' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse absolute address', () => { - const formula = '=$A$1' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse cell ref between strings', () => { - const formula = '="A5"+A4+"A6"' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse cell ref in string with escape', () => { - const formula = '="fdsaf\\"A5"' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse cell range from same sheet', () => { - const formula = '=$A$1:B$2' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse cell range from other sheet', () => { - const formula = '=Sheet1!$A$1:B$2' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse ops', () => { - const formula = '=-1+1-1*1/1^1&1=1<>1<1<=1>1<1' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse with unspecified error', () => { - const formula = '=1+' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=#ERROR!') - }) - - it('#unparse with known error', () => { - const formula = '=#REF!' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=#REF!') - }) - - it('#unparse error with data input', () => { - const cellReferenceExceedingMaxRowsLimit = '=A100' - const ast = parser.parse(cellReferenceExceedingMaxRowsLimit, adr('A1')).ast - - expect(ast.type).toEqual(AstNodeType.ERROR_WITH_RAW_INPUT) - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=A100') - }) - - it('#unparse with known error with translation', () => { - const config = new Config({language: 'plPL'}) - const parser = buildEmptyParserWithCaching(config, sheetMapping) - const unparser = new Unparser(config, sheetMapping, new NamedExpressions()) - const formula = '=#ADR!' - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=#ADR!') - }) - - it('#unparse forgets about downcase', () => { - const formula = '=sum(1, 2, 3)' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=SUM(1, 2, 3)') - }) - - it('#unparse should not forget about spaces', () => { - const formula = '= 1 + sum( 1,2, 3) +A1 / 2 + bar' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('= 1 + SUM( 1,2, 3) +A1 / 2 + bar') - }) - - it('#unparse named expression', () => { - const formula = '=true' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=true') - }) - - it('#unparse named expression returns original form', () => { - const namedExpressions = new NamedExpressions() - namedExpressions.addNamedExpression('SomeWEIRD_name', undefined) - const unparser = new Unparser(config, sheetMapping, namedExpressions) - const formula = '=someWeird_Name' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=SomeWEIRD_name') - }) - - it('#unparse named expression use local version if available', () => { - const namedExpressions = new NamedExpressions() - namedExpressions.addNamedExpression('SomeWEIRD_name', undefined) - namedExpressions.addNamedExpression('SomeWEIRD_NAME', 0) - const unparser = new Unparser(config, sheetMapping, namedExpressions) - const formula = '=someWeird_Name' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=SomeWEIRD_NAME') - }) - - it('#unparse nonexisting named expression returns original input', () => { - const namedExpressions = new NamedExpressions() - const unparser = new Unparser(config, sheetMapping, namedExpressions) - const formula = '=someWeird_Name' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=someWeird_Name') - }) - - it('#unparse nonexisting named expression returns original input when global named expression is removed', () => { - const namedExpressions = new NamedExpressions() - namedExpressions.addNamedExpression('SomeWEIRD_name', undefined) - namedExpressions.remove('SomeWEIRD_name', undefined) - const unparser = new Unparser(config, sheetMapping, namedExpressions) - const formula = '=someWeird_Name' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=someWeird_Name') - }) - - it('#unparse forgets about OFFSET', () => { - const formula = '=OFFSET(C3, 1, 1)' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=D4') - }) - - it('#unparse doesnt forget about unnecessary parenthesis', () => { - const formula = '=(1+2)' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=(1+2)') - }) - - it('#unparse do not forgets about sheet reference', () => { - const formula = '=Sheet1!C3' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=Sheet1!C3') - }) - - it('#unparse necessary parenthesis from left subtree', () => { - const formula = '=(1+2)*3' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=(1+2)*3') - }) - - it('#unparse necessary parenthesis from right subtree', () => { - const formula = '=3*(1+2)' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=3*(1+2)') - }) - - it('#unparse doesnt use parenthesis for the same operations', () => { - const formula = '=4*3*2' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=4*3*2') - }) - - it('#unparse doesnt use parenthesis for different operations of same precedece', () => { - const formula1 = '=4/3*2' - const formula2 = '=4*3/2' - const ast1 = parser.parse(formula1, adr('A1')).ast - const ast2 = parser.parse(formula2, adr('A1')).ast - - const unparsed1 = unparser.unparse(ast1, adr('A1')) - const unparsed2 = unparser.unparse(ast2, adr('A1')) - - expect(unparsed1).toEqual(formula1) - expect(unparsed2).toEqual(formula2) - }) - - it('#unparse doesnt use parenthesis for functions or other non-operator node types', () => { - const formula1 = '=TRUE()*2' - const formula2 = '=2*TRUE()' - const ast1 = parser.parse(formula1, adr('A1')).ast - const ast2 = parser.parse(formula2, adr('A1')).ast - - const unparsed1 = unparser.unparse(ast1, adr('A1')) - const unparsed2 = unparser.unparse(ast2, adr('A1')) - - expect(unparsed1).toEqual(formula1) - expect(unparsed2).toEqual(formula2) - }) - - it('#unparse necessary parenthesis from subtree', () => { - const formula = '=-(3+4)' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse double unary minus', () => { - const formula = '=-(-(3+4))' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse doesnt use parenthesis for non-operator node types', () => { - const formula = '=-42' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse percent', () => { - const formula = '=42%' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse use language configuration', () => { - const configEN = new Config({language: enGB.langCode}) - const configPL = new Config({language: plPL.langCode}) - - const parser = buildEmptyParserWithCaching(configPL, sheetMapping) - - const unparserPL = new Unparser(configPL, sheetMapping, new NamedExpressions()) - const unparserEN = new Unparser(configEN, sheetMapping, new NamedExpressions()) - - const formula = '=SUMA(1, 2)' - - const ast = parser.parse(formula, adr('A1')).ast - - expect(unparserPL.unparse(ast, adr('A1'))).toEqual('=SUMA(1, 2)') - expect(unparserEN.unparse(ast, adr('A1'))).toEqual('=SUM(1, 2)') - }) - - it('unparsing sheet names in references sometimes have to wrap in quotes', () => { - const formula = "='Sheet with spaces'!A1" - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('unparsing sheet names in quotes should escape single quotes', () => { - const formula = "='Sheet''With''Quotes'!A1" - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('unparsing sheet names in ranges sometimes have to wrap in quotes', () => { - const formula = "='Sheet with spaces'!A1:B1" - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1', 0)) - - expect(unparsed).toEqual(formula) - }) - - it('unparsing sheet name always returns its original name', () => { - const formula = '=shEET2!A1:B1' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1', 0)) - - expect(unparsed).toEqual('=Sheet2!A1:B1') - }) - - it('unparsing range with sheet name on both sides', () => { - const formula = '=Sheet1!A1:Sheet2!B1' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1', 0)) - - expect(unparsed).toEqual('=Sheet1!A1:Sheet2!B1') - }) - - it('unparsing function without translation should unparse to canonical name', () => { - const formula = '=FOOBAR(1, 2, 3)' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('=FOOBAR(1, 2, 3)') - }) - - it('unparsing numbers with decimal separator', () => { - const config = new Config({decimalSeparator: ',', functionArgSeparator: ';'}) - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(config, sheetMapping) - const unparser = new Unparser(config, sheetMapping, new NamedExpressions()) - const formula = '=1+1234,567' - - const ast = parser.parse(formula, adr('A1')).ast - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse column range', () => { - const formula = '=A:B' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse absolute column range', () => { - const formula = '=$A:B' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse column range from other sheet', () => { - const formula = '=Sheet1!$A:B' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse column range from other sheet - both sides', () => { - const formula = '=Sheet1!$A:Sheet1!B' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse row range', () => { - const formula = '=1:2' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse absolute row range', () => { - const formula = '=$1:2' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse row range from other sheet', () => { - const formula = '=Sheet1!$1:2' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) - - it('#unparse row range from other sheet - both sides', () => { - const formula = '=Sheet1!$1:Sheet1!2' - const ast = parser.parse(formula, adr('A1', 1)).ast - const unparsed = unparser.unparse(ast, adr('A1', 1)) - - expect(unparsed).toEqual(formula) - }) -}) - -describe('whitespaces', () => { - const config = new Config() - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - sheetMapping.addSheet('Sheet2') - sheetMapping.addSheet('Sheet with spaces') - const parser = buildEmptyParserWithCaching(config, sheetMapping) - const unparser = new Unparser(config, sheetMapping, new NamedExpressions()) - - it('should unparse with original whitespaces', () => { - const formula = '= 1' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should unparse string with original whitespaces', () => { - const formula = '= "foo"' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should unparse reference with original whitespaces', () => { - const formula = '= A1+ Sheet2!A1' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should unparse operators with original whitespaces', () => { - const formula = '= - 1 + 2 - 3 / 4 * 5 ^ 6 %' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should unparse ranges with leading whitespaces only', () => { - const formula = '= A1 : A2' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('= A1:A2') - }) - - it('should unparse formula with leading and internal whitespace', () => { - const formula = '= SUM( A1, A2 )' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should forget about spaces before func args separator', () => { - const formula = '= SUM( A1 , A2 )' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual('= SUM( A1, A2 )') - }) - - it('should unparse parenthesis with leading and internal whitespace', () => { - const formula = '=1 + ( A1 + A2 )' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should unparse error literals with leading whitespaces', () => { - const formula = '= #DIV/0!' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should unparse empty argument with whitespaces', () => { - const formula = '=PV(1,2,3, ,)' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('should unparse arrays with whitespaces', () => { - const formula = '= { 1, 2; 3, 4 }' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) - - it('when ignoreWhiteSpace = \'any\', should unparse a non-breakable space character', () => { - const config = new Config({ ignoreWhiteSpace: 'any' }) - const parser = buildEmptyParserWithCaching(config, sheetMapping) - const unparser = new Unparser(config, sheetMapping, new NamedExpressions()) - - const formula = '=\u00A01' - const ast = parser.parse(formula, adr('A1')).ast - - const unparsed = unparser.unparse(ast, adr('A1')) - - expect(unparsed).toEqual(formula) - }) -}) diff --git a/test/unit/parser/volatile-functions-detection.spec.ts b/test/unit/parser/volatile-functions-detection.spec.ts deleted file mode 100644 index 2482aabe17..0000000000 --- a/test/unit/parser/volatile-functions-detection.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {Config} from '../../../src/Config' -import {adr} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('ParserWithCaching - volatile functions detection', () => { - it('detects volatile functions', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=RAND()', adr('A1')) - expect(result.hasVolatileFunction).toBe(true) - }) - - it('detects volatile functions inside other functions', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=SUM(RAND())', adr('A1')) - expect(result.hasVolatileFunction).toBe(true) - }) - - it('detects volatile functions in unary operators', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=-RAND()', adr('A1')) - expect(result.hasVolatileFunction).toBe(true) - }) - - it('detects volatile functions in right arg of binary operators', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=42+RAND()', adr('A1')) - expect(result.hasVolatileFunction).toBe(true) - }) - - it('detects volatile functions in left arg of binary operators', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=RAND()+42', adr('A1')) - expect(result.hasVolatileFunction).toBe(true) - }) - - it('not all functions are volatile', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=SUM()', adr('A1')) - expect(result.hasVolatileFunction).toBe(false) - }) -}) - -describe('ParserWithCaching - structural change functions detection', () => { - it('detects volatile functions', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=COLUMNS()', adr('A1')) - expect(result.hasStructuralChangeFunction).toBe(true) - }) - - it('not all functions are dependent on structure changes', () => { - const parser = buildEmptyParserWithCaching(new Config()) - - const result = parser.parse('=SUM()', adr('A1')) - expect(result.hasStructuralChangeFunction).toBe(false) - }) -}) diff --git a/test/unit/parser/white-spaces.spec.ts b/test/unit/parser/white-spaces.spec.ts deleted file mode 100644 index 39d8d3e9d9..0000000000 --- a/test/unit/parser/white-spaces.spec.ts +++ /dev/null @@ -1,163 +0,0 @@ -import {Config} from '../../../src/Config' -import {SheetMapping} from '../../../src/DependencyGraph' -import {buildTranslationPackage} from '../../../src/i18n' -import {enGB} from '../../../src/i18n/languages' -import {buildLexerConfig, FormulaLexer} from '../../../src/parser' -import {CellReference, EqualsOp, ProcedureName, RangeSeparator, RParen} from '../../../src/parser/LexerConfig' -import {expectArrayWithSameContent} from '../testUtils' -import {buildEmptyParserWithCaching} from './common' - -describe('tokenizeFormula', () => { - const config = new Config() - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const lexer = new FormulaLexer(buildLexerConfig(config)) - - it('should not skip whitespaces', () => { - const tokens = lexer.tokenizeFormula('= A1 + 2').tokens - expect(tokens.length).toBe(7) - }) - - it('should forget about trailing whitespaces', () => { - const tokens = lexer.tokenizeFormula('=SUM(A1:A2) ').tokens - expect(tokens.map(token => token.tokenType.name)).not.toContain('WhiteSpace') - }) - - it('should skip whitespace inside range', () => { - const tokens = lexer.tokenizeFormula('=A1: A1').tokens - const tokenTypes = tokens.map(token => token.tokenType.name) - expectArrayWithSameContent(tokenTypes, ['EqualsOp', 'CellReference', 'RangeSeparator', 'CellReference']) - }) - - it('should skip whitespace inside range 2', () => { - const tokens = lexer.tokenizeFormula('=A1 :A1').tokens - const tokenTypes = tokens.map(token => token.tokenType.name) - expectArrayWithSameContent(tokenTypes, ['EqualsOp', 'CellReference', 'RangeSeparator', 'CellReference']) - }) - - it('should skip whitespace inside range 3', () => { - const tokens = lexer.tokenizeFormula('=A1 : A1').tokens - const tokenTypes = tokens.map(token => token.tokenType.name) - expectArrayWithSameContent(tokenTypes, ['EqualsOp', 'CellReference', 'RangeSeparator', 'CellReference']) - }) - - it('should not skip whitespaces before named expression', () => { - const tokens = lexer.tokenizeFormula('= A1 + TRUE').tokens - - const tokenTypes = tokens.map(token => token.tokenType.name) - expectArrayWithSameContent(tokenTypes, ['EqualsOp', 'WhiteSpace', 'CellReference', 'WhiteSpace', 'PlusOp', 'WhiteSpace', 'NamedExpression']) - }) - - it('should skip whitespace before function args separator', () => { - const tokens = lexer.tokenizeFormula('=SUM(A1 , A2)').tokens - const tokenTypes = tokens.map(token => token.tokenType.name) - - expectArrayWithSameContent(tokenTypes, ['EqualsOp', 'ProcedureName', 'CellReference', 'ArrayColSep', 'WhiteSpace', 'CellReference', 'RParen']) - }) - - it('should not skip whitespace when there is empty argument', () => { - const tokens = lexer.tokenizeFormula('=PV(A1 , ,A2)').tokens - const tokenTypes = tokens.map(token => token.tokenType.name) - - expect(tokenTypes).toEqual(['EqualsOp', 'ProcedureName', 'CellReference', 'ArrayColSep', 'WhiteSpace', 'ArrayColSep', 'CellReference', 'RParen']) - }) - - it('should treat space as whitespace', () => { - const tokens = lexer.tokenizeFormula('= 1').tokens - expect(tokens[1].tokenType.name).toEqual('WhiteSpace') - }) - - it('should treat tabulator (U+0009) as whitespace', () => { - const tokens = lexer.tokenizeFormula('=\t1').tokens - expect(tokens[1].tokenType.name).toEqual('WhiteSpace') - }) - - it('should treat carriage return (U+000D) as whitespace', () => { - const tokens = lexer.tokenizeFormula('=\r1').tokens - expect(tokens[1].tokenType.name).toEqual('WhiteSpace') - }) - - it('should treat line feed (U+000A) as whitespace', () => { - const tokens = lexer.tokenizeFormula('=\n1').tokens - expect(tokens[1].tokenType.name).toEqual('WhiteSpace') - }) - - it('should treat multiple whitespaces as one token', () => { - const tokens = lexer.tokenizeFormula('=\n\t\r 1').tokens - expect(tokens.length).toEqual(3) - expect(tokens[1].tokenType.name).toEqual('WhiteSpace') - expect(tokens[1].image).toEqual('\n\t\r ') - }) - - it('when set ignoreWhiteSpace = \'any\', should treat non-breaking space as a whitespace', () => { - const config = new Config({ ignoreWhiteSpace: 'any' }) - const lexer = new FormulaLexer(buildLexerConfig(config)) - - const tokens = lexer.tokenizeFormula('=\u00A042').tokens - expect(tokens[1].tokenType.name).toEqual('WhiteSpace') - }) -}) - -describe('processWhitespaces', () => { - const config = new Config() - const sheetMapping = new SheetMapping(buildTranslationPackage(enGB)) - sheetMapping.addSheet('Sheet1') - const parser = buildEmptyParserWithCaching(config, sheetMapping) - - it('should do nothing when no whitespaces', () => { - const tokens = parser.tokenizeFormula('=SUM(A1:A2)').tokens - const processed = parser.bindWhitespacesToTokens(tokens) - expect(processed.length).toBe(6) - expect(processed.map(processed => processed.leadingWhitespace).every(processed => processed === undefined)).toBe(true) - expectArrayWithSameContent( - [EqualsOp, ProcedureName, CellReference, RangeSeparator, CellReference, RParen], - processed.map(token => token.tokenType) - ) - }) - - it('should add leading whitespace to token', () => { - const tokens = parser.tokenizeFormula('= SUM(A1:A2)').tokens - const processed = parser.bindWhitespacesToTokens(tokens) - expect(processed.length).toBe(6) - - expect(processed[1].leadingWhitespace!.image).toBe(' ') - expectArrayWithSameContent( - [EqualsOp, ProcedureName, CellReference, RangeSeparator, CellReference, RParen], - processed.map(token => token.tokenType) - ) - }) - - it('should work for multiple whitespaces', () => { - const tokens = parser.tokenizeFormula('= SUM(A1:A2)').tokens - const processed = parser.bindWhitespacesToTokens(tokens) - expect(processed.length).toBe(6) - - expect(processed[1].leadingWhitespace!.image).toBe(' ') - expectArrayWithSameContent( - [EqualsOp, ProcedureName, CellReference, RangeSeparator, CellReference, RParen], - processed.map(token => token.tokenType) - ) - }) - - it('should work for whitespace at the beginning', () => { - const tokens = parser.tokenizeFormula(' =SUM(A1:A2)').tokens - const processed = parser.bindWhitespacesToTokens(tokens) - expect(processed.length).toBe(6) - - expect(processed[0].leadingWhitespace!.image).toBe(' ') - expectArrayWithSameContent( - [EqualsOp, ProcedureName, CellReference, RangeSeparator, CellReference, RParen], - processed.map(token => token.tokenType) - ) - }) - - it('should not include whitespaces directly on the list', () => { - const tokens = parser.tokenizeFormula('= SUM( A1:A2) ').tokens - const processed = parser.bindWhitespacesToTokens(tokens) - expect(processed.length).toBe(6) - expectArrayWithSameContent( - [EqualsOp, ProcedureName, CellReference, RangeSeparator, CellReference, RParen], - processed.map(token => token.tokenType) - ) - }) -}) diff --git a/test/unit/range-mapping.spec.ts b/test/unit/range-mapping.spec.ts deleted file mode 100644 index b3ac938f76..0000000000 --- a/test/unit/range-mapping.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import {AbsoluteCellRange, AbsoluteColumnRange} from '../../src/AbsoluteCellRange' -import {RangeMapping, RangeVertex} from '../../src/DependencyGraph' -import {adr, colEnd, colStart} from './testUtils' - -describe('RangeMapping', () => { - it('range mapping when there is none', () => { - const mapping = new RangeMapping() - const start = adr('A1') - const end = adr('U50') - - expect(mapping.getRangeVertex(start, end)).toBe(undefined) - }) - - it('setting range mapping', () => { - const mapping = new RangeMapping() - const start = adr('A1') - const end = adr('U50') - const vertex = new RangeVertex(new AbsoluteCellRange(start, end)) - - mapping.addOrUpdateVertex(vertex) - - expect(mapping.getRangeVertex(start, end)).toBe(vertex) - }) - - it('set column range', () => { - const mapping = new RangeMapping() - const start = colStart('A') - const end = colEnd('U') - const vertex = new RangeVertex(new AbsoluteColumnRange(start.sheet, start.col, end.col)) - - mapping.addOrUpdateVertex(vertex) - - expect(mapping.getRangeVertex(start, end)).toBe(vertex) - }) -}) diff --git a/test/unit/range-vertex.spec.ts b/test/unit/range-vertex.spec.ts deleted file mode 100644 index c099254eaf..0000000000 --- a/test/unit/range-vertex.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {Config} from '../../src/Config' -import {DateTimeHelper} from '../../src/DateTimeHelper' -import {CriterionCache, RangeVertex} from '../../src/DependencyGraph' -import {ArithmeticHelper} from '../../src/interpreter/ArithmeticHelper' -import {buildCriterionLambda, CriterionBuilder} from '../../src/interpreter/Criterion' -import {NumberLiteralHelper} from '../../src/NumberLiteralHelper' -import {adr} from './testUtils' - -describe('RangeVertex with cache', () => { - it('cache for criterion fuctions empty', () => { - const rangeVertex = new RangeVertex(new AbsoluteCellRange(adr('B2'), adr('B11'))) - - expect(rangeVertex.getCriterionFunctionValues('SUMIF,1,1').size).toBe(0) - }) - - it('cache for functions with criterion basic usage', () => { - const config = new Config() - const dateHelper = new DateTimeHelper(config) - const numberLiteralsHelper = new NumberLiteralHelper(config) - const arithmeticHelper = new ArithmeticHelper(config, dateHelper, numberLiteralsHelper) - const criterionBuilder = new CriterionBuilder(config) - - const rangeVertex = new RangeVertex(new AbsoluteCellRange(adr('B2'), adr('B11'))) - - const criterionString1 = '>=0' - - const criterion1 = buildCriterionLambda(criterionBuilder.parseCriterion(criterionString1, arithmeticHelper)!, arithmeticHelper) - - const criterionString2 = '=1' - - const criterion2 = buildCriterionLambda(criterionBuilder.parseCriterion(criterionString2, arithmeticHelper)!, arithmeticHelper) - - const criterionCache: CriterionCache = new Map() - - criterionCache.set(criterionString1, [10, [criterion1]]) - criterionCache.set(criterionString2, [20, [criterion2]]) - - rangeVertex.setCriterionFunctionValues('SUMIF,1,1', criterionCache) - - expect(rangeVertex.getCriterionFunctionValues('SUMIF,1,1').size).toBe(2) - expect(rangeVertex.getCriterionFunctionValue('SUMIF,1,1', criterionString1)).toEqual(10) - expect(rangeVertex.getCriterionFunctionValue('SUMIF,1,1', criterionString2)).toEqual(20) - }) -}) diff --git a/test/unit/ranges.spec.ts b/test/unit/ranges.spec.ts deleted file mode 100644 index 07a0db1316..0000000000 --- a/test/unit/ranges.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {adr, detailedError} from './testUtils' -import {ErrorMessage} from '../../src/error-message' - -describe('Ranges', () => { - describe('when operating on infinite ranges', () => { - describe('with array arithmetic on', () => { - it('returns a cell error, when operation results in an infinite column range not starting on index 0 (setCellContents)', () => { - const engine = HyperFormula.buildFromArray([[1, 2]], { useArrayArithmetic: true }) - engine.setCellContents(adr('B2'), '=A:A+B1') - - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.ERROR, 'Invalid range size')) - }) - - it('returns a cell error, when operation results in a range with infinite width and infinite height (setCellContents)', () => { - const engine = HyperFormula.buildFromArray([[1]], { useArrayArithmetic: true }) - engine.setCellContents(adr('B2'), '=A:A+1:1') - - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.ERROR, 'Invalid range size')) - }) - - it('returns a #SPILL error, when operation results in an infinite column range not starting on index 0', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [null, '=A:A+B1']], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - }) - - it('returns a #SPILL error, when operation results in a range with infinite width and infinite height', () => { - const engine = HyperFormula.buildFromArray([[], [null, '=A:A+1:1']], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - }) - }) - - describe('with array arithmetic off', () => { - it('calculates the value according to the rules for array arithmetic mode disabled, when evaluating an operation on a column range and a single element (setCellContents)', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [3]], { useArrayArithmetic: false }) - engine.setCellContents(adr('B2'), '=A:A+B1') - - expect(engine.getSheetValues(0)).toEqual([[1, 2], [3, 5]]) - }) - - it('calculates the value according to the rules for array arithmetic mode disabled, when evaluating an operation on a column range and a row range (setCellContents)', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [3]], { useArrayArithmetic: false }) - engine.setCellContents(adr('B2'), '=A:A+1:1') - - expect(engine.getSheetValues(0)).toEqual([[1, 2], [3, 5]]) - }) - - it('returns a #SPILL error, when evaluating an operation on a column range and a single element', () => { - const engine = HyperFormula.buildFromArray([[1, 2], [null, '=A:A+B1']], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - }) - - it('returns a #SPILL error, when evaluating an operation on a column range and a row range', () => { - const engine = HyperFormula.buildFromArray([[], [null, '=A:A+1:1']], { useArrayArithmetic: true }) - - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult)) - }) - }) - }) -}) diff --git a/test/unit/rebuild.spec.ts b/test/unit/rebuild.spec.ts deleted file mode 100644 index b66951a751..0000000000 --- a/test/unit/rebuild.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {ErrorMessage} from '../../src/error-message' -import {adr, detailedError, resetSpy} from './testUtils' -import {BuildEngineFactory} from '../../src/BuildEngineFactory' - -describe('Rebuilding engine', () => { - it('should preserve absolute named expression', () => { - const engine = HyperFormula.buildFromArray([['=FALSE']]) - engine.addNamedExpression('FALSE', '=FALSE()') - engine.rebuildAndRecalculate() - expect(engine.getCellValue(adr('A1'))).toEqual(false) - }) - - it('should preserve local named expression', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=FALSE']], - 'Sheet2': [['=FALSE']] - }) - engine.addNamedExpression('FALSE', '=FALSE()', 0) - engine.rebuildAndRecalculate() - expect(engine.getCellValue(adr('A1', 0))).toEqual(false) - expect(engine.getCellValue(adr('A1', 1))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('FALSE'))) - }) - - it('named references should work after rebuild', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['42', '=FOO']], - }) - engine.addNamedExpression('FOO', '=Sheet1!$A$1') - engine.rebuildAndRecalculate() - - expect(engine.getCellValue(adr('B1', 0))).toEqual(42) - }) - - it('scopes are properly handled', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['42']], - 'Sheet2': [['42', '=FALSE']], - }, {}, [{name: 'FALSE', expression: false, scope: 1}]) - - engine.removeSheet(0) - engine.rebuildAndRecalculate() - expect(engine.getCellValue(adr('B1'))).toEqual(false) - }) - - it('rebuildAndRecalculate rebuilds the engine if the config is empty', () => { - const engine = HyperFormula.buildFromArray([[]], {}) - - const rebuildEngineSpy = spyOn(BuildEngineFactory, 'rebuildWithConfig') - resetSpy(rebuildEngineSpy) - - engine.rebuildAndRecalculate() - - expect(rebuildEngineSpy).toHaveBeenCalled() - }) - - it('doesn\'t throw after adding named expression (#1194)', () => { - const hf = HyperFormula.buildFromArray([['=42']], { - licenseKey: 'gpl-v3' - }) - - - hf.addNamedExpression('ABC', '=Sheet1!$A$1') - expect(() => hf.rebuildAndRecalculate()).not.toThrow() - }) -}) diff --git a/test/unit/row-range.spec.ts b/test/unit/row-range.spec.ts deleted file mode 100644 index 1c1e36666d..0000000000 --- a/test/unit/row-range.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import {HyperFormula} from '../../src' -import {adr, rowEnd, rowStart} from './testUtils' - -describe('Row ranges', () => { - it('should work', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['=SUM(1:2)'] - ]) - - expect(engine.getCellValue(adr('A3'))).toEqual(3) - }) - - it('should create correct edges for infinite range when building graph', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(3:4)'], - ['=SUM(C3:D4)'], - ]) - - const rowRange = engine.rangeMapping.getRangeVertex(rowStart(3), rowEnd(4))! - - const c3 = engine.dependencyGraph.fetchCell(adr('C3')) - const c4 = engine.dependencyGraph.fetchCell(adr('C4')) - const d3 = engine.dependencyGraph.fetchCell(adr('D3')) - const d4 = engine.dependencyGraph.fetchCell(adr('D4')) - - expect(engine.graph.existsEdge(c3, rowRange)).toBe(true) - expect(engine.graph.existsEdge(c4, rowRange)).toBe(true) - expect(engine.graph.existsEdge(d3, rowRange)).toBe(true) - expect(engine.graph.existsEdge(d4, rowRange)).toBe(true) - }) - - it('should create correct edges for infinite range', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(3:5)'], - ['=SUM(4:7)'], - ]) - - engine.setCellContents(adr('B1'), '=SUM(Z4:Z8)') - - const rowRange35 = engine.rangeMapping.getRangeVertex(rowStart(3), rowEnd(5))! - const rowRange47 = engine.rangeMapping.getRangeVertex(rowStart(4), rowEnd(7))! - - const z4 = engine.dependencyGraph.fetchCell(adr('Z4')) - const z5 = engine.dependencyGraph.fetchCell(adr('Z5')) - const z6 = engine.dependencyGraph.fetchCell(adr('Z6')) - const z7 = engine.dependencyGraph.fetchCell(adr('Z7')) - const z8 = engine.dependencyGraph.fetchCell(adr('Z8')) - - expect(engine.graph.existsEdge(z4, rowRange35)).toBe(true) - expect(engine.graph.existsEdge(z5, rowRange35)).toBe(true) - expect(engine.graph.existsEdge(z6, rowRange35)).toBe(false) - - expect(engine.graph.existsEdge(z4, rowRange47)).toBe(true) - expect(engine.graph.existsEdge(z5, rowRange47)).toBe(true) - expect(engine.graph.existsEdge(z6, rowRange47)).toBe(true) - expect(engine.graph.existsEdge(z7, rowRange47)).toBe(true) - expect(engine.graph.existsEdge(z8, rowRange47)).toBe(false) - }) - - it('should correctly handle infinite row ranges when setting cell values (line 890)', () => { - const engine = HyperFormula.buildFromArray([ - ['=SUM(3:4)'], - ]) - - expect(engine.getCellValue(adr('A1'))).toBe(0) - - engine.setCellContents(adr('E3'), 100) - engine.setCellContents(adr('F4'), 200) - - expect(engine.getCellValue(adr('A1'))).toBe(300) - }) -}) diff --git a/test/unit/scoped-namedExpressions.spec.ts b/test/unit/scoped-namedExpressions.spec.ts deleted file mode 100644 index 01ab56d5ca..0000000000 --- a/test/unit/scoped-namedExpressions.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {HyperFormula} from '../../src' -import {adr} from './testUtils' - -describe('scoped named expressions', () => { - it('should be removed when sheet is removed', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[]], 'Sheet2': [[]]}) - engine.addNamedExpression('TRUE', true, 0) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - expect(engine._namedExpressions.getAllNamedExpressionsNames()).toEqual(['TRUE']) - engine.removeSheet(0) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - expect(engine._namedExpressions.getAllNamedExpressionsNames()).toEqual([]) - }) - - it('removal should work with undo of sheet', () => { - const engine = HyperFormula.buildFromArray([['=TRUE']]) - engine.addNamedExpression('TRUE', true, 0) - engine.removeSheet(0) - engine.undo() - expect(engine.getCellValue(adr('A1'))).toEqual(true) - }) - - it('removal should work with undo of named expression', () => { - const engine = HyperFormula.buildFromArray([['=TRUE']]) - engine.addNamedExpression('TRUE', true, 0) - engine.removeNamedExpression('TRUE', 0) - engine.undo() - expect(engine.getCellValue(adr('A1'))).toEqual(true) - }) -}) diff --git a/test/unit/serialization.spec.ts b/test/unit/serialization.spec.ts deleted file mode 100644 index 38abef07d7..0000000000 --- a/test/unit/serialization.spec.ts +++ /dev/null @@ -1,124 +0,0 @@ -import {HyperFormula} from '../../src' -import {CellValueDetailedType} from '../../src/Cell' -import {adr} from './testUtils' - -describe('serialization', () => { - it('should not loose sheet information on serialization', () => { - const engine1 = HyperFormula.buildFromArray([ - [1, '2', 'foo', true, '\'1', '33$', '12/01/15', '1%', '=FOO(', '#DIV/0!', new Date(1995, 11, 17)] - ]) - - expect(engine1.getCellSerialized(adr('A1'))).toEqual(1) - expect(engine1.getCellValueFormat(adr('A1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_RAW) - - expect(engine1.getCellSerialized(adr('B1'))).toEqual('2') - expect(engine1.getCellValueFormat(adr('B1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('B1'))).toEqual(CellValueDetailedType.NUMBER_RAW) - - expect(engine1.getCellSerialized(adr('C1'))).toEqual('foo') - expect(engine1.getCellValueFormat(adr('C1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('C1'))).toEqual(CellValueDetailedType.STRING) - - expect(engine1.getCellSerialized(adr('D1'))).toEqual(true) - expect(engine1.getCellValueFormat(adr('D1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('D1'))).toEqual(CellValueDetailedType.BOOLEAN) - - expect(engine1.getCellSerialized(adr('E1'))).toEqual('\'1') - expect(engine1.getCellValueFormat(adr('E1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('E1'))).toEqual(CellValueDetailedType.STRING) - - expect(engine1.getCellSerialized(adr('F1'))).toEqual('33$') - expect(engine1.getCellValueFormat(adr('F1'))).toEqual('$') - expect(engine1.getCellValueDetailedType(adr('F1'))).toEqual(CellValueDetailedType.NUMBER_CURRENCY) - - expect(engine1.getCellSerialized(adr('G1'))).toEqual('12/01/15') - expect(engine1.getCellValueFormat(adr('G1'))).toEqual('DD/MM/YY') - expect(engine1.getCellValueDetailedType(adr('G1'))).toEqual(CellValueDetailedType.NUMBER_DATE) - - expect(engine1.getCellSerialized(adr('H1'))).toEqual('1%') - expect(engine1.getCellValueFormat(adr('H1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('H1'))).toEqual(CellValueDetailedType.NUMBER_PERCENT) - - expect(engine1.getCellSerialized(adr('I1'))).toEqual('=FOO(') - expect(engine1.getCellValueFormat(adr('I1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('I1'))).toEqual(CellValueDetailedType.ERROR) - - expect(engine1.getCellSerialized(adr('J1'))).toEqual('#DIV/0!') - expect(engine1.getCellValueFormat(adr('J1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('J1'))).toEqual(CellValueDetailedType.ERROR) - - expect(engine1.getCellSerialized(adr('K1'))).toEqual(new Date(1995, 11, 17)) - expect(engine1.getCellValueFormat(adr('K1'))).toEqual('Date()') - expect(engine1.getCellValueDetailedType(adr('K1'))).toEqual(CellValueDetailedType.NUMBER_DATE) - - // serialize and "send" data to server - const serialized = engine1.getAllSheetsSerialized() - - // reload data and "restore" the previous state - const engine2 = HyperFormula.buildFromSheets(serialized) - - expect(engine2.getCellSerialized(adr('A1'))).toEqual(1) - expect(engine2.getCellValueFormat(adr('A1'))).toEqual(undefined) - expect(engine2.getCellValueDetailedType(adr('A1'))).toEqual(CellValueDetailedType.NUMBER_RAW) - - expect(engine2.getCellSerialized(adr('B1'))).toEqual('2') - expect(engine2.getCellValueFormat(adr('B1'))).toEqual(undefined) - expect(engine2.getCellValueDetailedType(adr('B1'))).toEqual(CellValueDetailedType.NUMBER_RAW) - - expect(engine2.getCellSerialized(adr('C1'))).toEqual('foo') - expect(engine2.getCellValueFormat(adr('C1'))).toEqual(undefined) - expect(engine2.getCellValueDetailedType(adr('C1'))).toEqual(CellValueDetailedType.STRING) - - expect(engine2.getCellSerialized(adr('D1'))).toEqual(true) - expect(engine2.getCellValueFormat(adr('D1'))).toEqual(undefined) - expect(engine2.getCellValueDetailedType(adr('D1'))).toEqual(CellValueDetailedType.BOOLEAN) - - expect(engine2.getCellSerialized(adr('E1'))).toEqual('\'1') - expect(engine2.getCellValueFormat(adr('E1'))).toEqual(undefined) - expect(engine2.getCellValueDetailedType(adr('E1'))).toEqual(CellValueDetailedType.STRING) - - expect(engine2.getCellSerialized(adr('F1'))).toEqual('33$') - expect(engine2.getCellValueFormat(adr('F1'))).toEqual('$') - expect(engine2.getCellValueDetailedType(adr('F1'))).toEqual(CellValueDetailedType.NUMBER_CURRENCY) - - expect(engine2.getCellSerialized(adr('G1'))).toEqual('12/01/15') - expect(engine2.getCellValueFormat(adr('G1'))).toEqual('DD/MM/YY') - expect(engine2.getCellValueDetailedType(adr('G1'))).toEqual(CellValueDetailedType.NUMBER_DATE) - - expect(engine1.getCellSerialized(adr('H1'))).toEqual('1%') - expect(engine1.getCellValueFormat(adr('H1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('H1'))).toEqual(CellValueDetailedType.NUMBER_PERCENT) - - expect(engine1.getCellSerialized(adr('I1'))).toEqual('=FOO(') - expect(engine1.getCellValueFormat(adr('I1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('I1'))).toEqual(CellValueDetailedType.ERROR) - - expect(engine1.getCellSerialized(adr('J1'))).toEqual('#DIV/0!') - expect(engine1.getCellValueFormat(adr('J1'))).toEqual(undefined) - expect(engine1.getCellValueDetailedType(adr('J1'))).toEqual(CellValueDetailedType.ERROR) - - expect(engine1.getCellSerialized(adr('K1'))).toEqual(new Date(1995, 11, 17)) - expect(engine1.getCellValueFormat(adr('K1'))).toEqual('Date()') - expect(engine1.getCellValueDetailedType(adr('K1'))).toEqual(CellValueDetailedType.NUMBER_DATE) - }) - - it('should return raw value for array formula spill cells', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=TRANSPOSE(A1:C1)'], - ], { useArrayArithmetic: true }) - - expect(engine.getCellSerialized(adr('A2'))).toEqual('=TRANSPOSE(A1:C1)') - }) - - it('should return raw value for array formula non-top-left cells', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2, 3], - ['=TRANSPOSE(A1:C1)'], - ], { useArrayArithmetic: true }) - - expect(engine.getCellSerialized(adr('A3'))).toEqual(2) - expect(engine.getCellSerialized(adr('A4'))).toEqual(3) - }) -}) diff --git a/test/unit/small-build.spec.ts b/test/unit/small-build.spec.ts deleted file mode 100644 index 8df2b22ee1..0000000000 --- a/test/unit/small-build.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {HyperFormula} from '../../src' - -describe('Small tests that check evaluation order', () => { - it('passes #1', () => { - const engine = HyperFormula.buildFromArray([ - [500, '=(1-B2)*A1', '=(1-B2)*B1'], - ['=A1', 0.2, '=B2'], - ]) - expect(engine.getSheetValues(0)).toEqual([ - [500, 400, 320], - [500, 0.2, 0.2] - ]) - }) - - it('passes #2', () => { - const engine = HyperFormula.buildFromArray([ - [500, '=(1-B2)*A2', '=(1-C2)*B1'], - ['=A1', 0.2, '=B2'], - ]) - expect(engine.getSheetValues(0)).toEqual([ - [500, 400, 320], - [500, 0.2, 0.2] - ]) - }) -}) diff --git a/test/unit/small-setcellcontent.spec.ts b/test/unit/small-setcellcontent.spec.ts deleted file mode 100644 index 0ff5e2f163..0000000000 --- a/test/unit/small-setcellcontent.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {ErrorType, HyperFormula} from '../../src' -import {detailedErrorWithOrigin} from './testUtils' - -describe('should properly build', () => { - it('for this test', () => { - const engine = HyperFormula.buildEmpty() - engine.addSheet() - engine.setSheetContent(0, [ - ['=MAX(B1:B2)', '=MAX(A1:A2)'], - ['=MAX(B1:B2)', '=MAX(A1:A2)'], - ]) - expect(engine.getSheetValues(0)).toEqual( - [ - [detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1'), detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B1')], - [detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A2'), detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B2')], - ] - ) - }) - - it('and for this', () => { - const engine = HyperFormula.buildFromArray([ - ['=MAX(B1:B2)', '=MAX(A1:A2)'], - ['=MAX(B1:B2)', '=MAX(A1:A2)'], - ]) - expect(engine.getSheetValues(0)).toEqual( - [ - [detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A1'), detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B1')], - [detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!A2'), detailedErrorWithOrigin(ErrorType.CYCLE, 'Sheet1!B2')], - ] - ) - }) -}) diff --git a/test/unit/statistics/statistics.spec.ts b/test/unit/statistics/statistics.spec.ts deleted file mode 100644 index 5ecdefb62c..0000000000 --- a/test/unit/statistics/statistics.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {Statistics, StatType} from '../../../src/statistics' - -describe('Statistics', () => { - - it('reset - should return to base values', () => { - const statistics = new Statistics() - - const baseSnapshot = statistics.snapshot() - - statistics.start(StatType.BUILD_ENGINE_TOTAL) - statistics.end(StatType.BUILD_ENGINE_TOTAL) - statistics.start(StatType.VLOOKUP) - statistics.end(StatType.VLOOKUP) - statistics.start(StatType.PROCESS_DEPENDENCIES) - statistics.end(StatType.PROCESS_DEPENDENCIES) - statistics.incrementCriterionFunctionFullCacheUsed() - statistics.incrementCriterionFunctionPartialCacheUsed() - - const modifiedSnapshot = statistics.snapshot() - - statistics.reset() - - const resetSnapshot = statistics.snapshot() - - expect(baseSnapshot.size).toEqual(2) - expect(baseSnapshot.get(StatType.CRITERION_FUNCTION_FULL_CACHE_USED)).toEqual(0) - expect(baseSnapshot.get(StatType.CRITERION_FUNCTION_PARTIAL_CACHE_USED)).toEqual(0) - - expect(modifiedSnapshot.size).toEqual(5) - expect(modifiedSnapshot.has(StatType.CRITERION_FUNCTION_FULL_CACHE_USED)).toEqual(true) - expect(modifiedSnapshot.has(StatType.CRITERION_FUNCTION_PARTIAL_CACHE_USED)).toEqual(true) - expect(modifiedSnapshot.has(StatType.BUILD_ENGINE_TOTAL)).toEqual(true) - expect(modifiedSnapshot.has(StatType.VLOOKUP)).toEqual(true) - expect(modifiedSnapshot.has(StatType.PROCESS_DEPENDENCIES)).toEqual(true) - - expect(resetSnapshot).toEqual(baseSnapshot) - }) - - it('start - should throw if you try and start multiple of the same StatType', () => { - const statistics = new Statistics() - - statistics.start(StatType.BUILD_ENGINE_TOTAL) - statistics.start(StatType.VLOOKUP) - - expect(() => { - statistics.start(StatType.BUILD_ENGINE_TOTAL) - }).toThrowError(`Statistics ${StatType.BUILD_ENGINE_TOTAL} already started`) - - expect(() => { - statistics.start(StatType.VLOOKUP) - }).toThrowError(`Statistics ${StatType.VLOOKUP} already started`) - }) - - it('end - should throw if you try and end a StatType that has not been started', () => { - const statistics = new Statistics() - - statistics.start(StatType.BUILD_ENGINE_TOTAL) - statistics.start(StatType.VLOOKUP) - - expect(() => { - statistics.end(StatType.PROCESS_DEPENDENCIES) - }).toThrowError(`Statistics ${StatType.PROCESS_DEPENDENCIES} not started`) - - expect(() => { - statistics.end(StatType.ADJUSTING_ADDRESS_MAPPING) - }).toThrowError(`Statistics ${StatType.ADJUSTING_ADDRESS_MAPPING} not started`) - }) - -}) diff --git a/test/unit/temporary-formulas.spec.ts b/test/unit/temporary-formulas.spec.ts deleted file mode 100644 index 648f9a5061..0000000000 --- a/test/unit/temporary-formulas.spec.ts +++ /dev/null @@ -1,151 +0,0 @@ -import {HyperFormula} from '../../src' -import {NotAFormulaError} from '../../src/errors' - -describe('Temporary formulas - normalization', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([]) - - const normalizedFormula = engine.normalizeFormula('=SHEET1!A1+10') - - expect(normalizedFormula).toEqual('=Sheet1!A1+10') - }) - - it('fail with a typo', () => { - const engine = HyperFormula.buildFromArray([]) - - const normalizedFormula = engine.normalizeFormula('=SHET1!A1+10') - const normalizedFormula2 = engine.normalizeFormula('=SUM(SHET1!A1:A100)') - - expect(normalizedFormula).toEqual('=SHET1!A1+10') - expect(normalizedFormula2).toEqual('=SUM(SHET1!A1:A100)') - }) - - it('works with absolute addressing', () => { - const engine = HyperFormula.buildFromArray([]) - - const normalizedFormula = engine.normalizeFormula('=3*$a$1') - - expect(normalizedFormula).toEqual('=3*$A$1') - }) - - it('wont normalize sheet names of not existing sheets', () => { - const engine = HyperFormula.buildEmpty() - - const formula = '=ShEeT1!A1+10' - - expect(engine.normalizeFormula(formula)).toBe('=ShEeT1!A1+10') - }) - - it('throws an error if formulaString is malformed', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => { - engine.normalizeFormula('=#FOO!') - }).toThrow(new NotAFormulaError()) - }) -}) - -describe('Temporary formulas - validation', () => { - it('ok for formulas', () => { - const engine = HyperFormula.buildFromArray([]) - - const formula = '=Sheet1!A1+10' - - expect(engine.validateFormula(formula)).toBe(true) - }) - - it('fail for simple values', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.validateFormula('42')).toBe(false) - expect(engine.validateFormula('some text')).toBe(false) - }) - - it('fail when not a formula', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.validateFormula('=SOME SYNTAX ERRORS')).toBe(false) - }) - - it('ok when literal error', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(engine.validateFormula('=#N/A')).toBe(true) - }) - - it('validateFormula fails with an empty engine', () => { - const engine = HyperFormula.buildEmpty() - - const formula = '=Sheet1!A1+10' - - expect(engine.validateFormula(formula)).toBe(true) - }) -}) - -describe('Temporary formulas - calculation', () => { - it('basic usage', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - - const result = engine.calculateFormula('=Sheet1!A1+10', 0) - - expect(result).toEqual(52) - }) - - it('formulas are executed in context of given sheet', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['42']], - Sheet2: [['58']], - }) - - expect(engine.calculateFormula('=A1+10', 0)).toEqual(52) - expect(engine.calculateFormula('=A1+10', 1)).toEqual(68) - }) - - it('when sheet name does not exist', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ]) - - expect(() => { - engine.calculateFormula('=Sheet1!A1+10', 1) - }).toThrowError(/no sheet with id/) - }) - - it('SUM with range args', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['3', '4'] - ]) - expect(engine.calculateFormula('=SUM(A1:B2)', 0)).toEqual(10) - }) - - it('non-scalars work', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['1', '2'], - ]) - - const result = engine.calculateFormula('=TRANSPOSE(A1:B2)', 0) - - expect(result).toEqual([[1, 1], [2, 2]]) - }) - - it('more non-scalars', () => { - const engine = HyperFormula.buildFromArray([[0, 1]]) - expect(engine.calculateFormula('=ARRAYFORMULA(ISEVEN(A1:B2*3))', 0)).toEqual([[true, false], [true, true]]) - }) - - it('passing something which is not a formula doesnt work', () => { - const engine = HyperFormula.buildFromArray([]) - - expect(() => { - engine.calculateFormula('{=TRANSPOSE(A1:B2)}', 0) - }).toThrowError(/not a formula/) - - expect(() => { - engine.calculateFormula('42', 0) - }).toThrowError(/not a formula/) - }) -}) diff --git a/test/unit/testUtils.spec.ts b/test/unit/testUtils.spec.ts deleted file mode 100644 index b9155ca22e..0000000000 --- a/test/unit/testUtils.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {Config} from '../../src/Config' -import {dateNumberToString} from './testUtils' - -describe('test utils', () => { - it('#dateNumberToString should return properly formatted date', () => { - expect(dateNumberToString(0, new Config())).toEqual('30/12/1899') - expect(dateNumberToString(2, new Config())).toEqual('01/01/1900') - expect(dateNumberToString(43465, new Config())).toEqual('31/12/2018') - }) -}) diff --git a/test/unit/testUtils.ts b/test/unit/testUtils.ts deleted file mode 100644 index 41579e5c2e..0000000000 --- a/test/unit/testUtils.ts +++ /dev/null @@ -1,280 +0,0 @@ -import {CellValue, DetailedCellError, ErrorType, HyperFormula, RawCellContent, Sheet, SheetDimensions} from '../../src' -import {AbsoluteCellRange, AbsoluteColumnRange, AbsoluteRowRange} from '../../src/AbsoluteCellRange' -import {CellError, SimpleCellAddress, simpleCellAddress} from '../../src/Cell' -import {Config} from '../../src/Config' -import {DateTimeHelper} from '../../src/DateTimeHelper' -import {ArrayFormulaVertex, ScalarFormulaVertex, Graph, RangeVertex} from '../../src/DependencyGraph' -import {ErrorMessage} from '../../src/error-message' -import {defaultStringifyDateTime} from '../../src/format/format' -import {complex} from '../../src/interpreter/ArithmeticHelper' -import {ColumnIndex} from '../../src/Lookup/ColumnIndex' -import { - AstNodeType, - CellAddress, - CellRangeAst, - CellReferenceAst, - ErrorAst, - ProcedureAst, - simpleCellAddressToString, -} from '../../src/parser' -import {ColumnRangeAst, RowRangeAst} from '../../src/parser/Ast' -import {EngineComparator} from './graphComparator' - -export const extractReference = (engine: HyperFormula, address: SimpleCellAddress): CellAddress => { - return ((engine.addressMapping.getCell(address) as ScalarFormulaVertex).getFormula(engine.lazilyTransformingAstService) as CellReferenceAst).reference -} - -export const extractRange = (engine: HyperFormula, address: SimpleCellAddress): AbsoluteCellRange => { - const formula = (engine.addressMapping.getCell(address) as ScalarFormulaVertex).getFormula(engine.lazilyTransformingAstService) as ProcedureAst - const rangeAst = formula.args[0] as CellRangeAst - return new AbsoluteCellRange(rangeAst.start.toSimpleCellAddress(address), rangeAst.end.toSimpleCellAddress(address)) -} - -export const extractColumnRange = (engine: HyperFormula, address: SimpleCellAddress): AbsoluteColumnRange => { - const formula = (engine.addressMapping.getCell(address) as ScalarFormulaVertex).getFormula(engine.lazilyTransformingAstService) as ProcedureAst - const rangeAst = formula.args[0] as ColumnRangeAst - return AbsoluteColumnRange.fromColumnRange(rangeAst, address) -} - -export const extractRowRange = (engine: HyperFormula, address: SimpleCellAddress): AbsoluteRowRange => { - const formula = (engine.addressMapping.getCell(address) as ScalarFormulaVertex).getFormula(engine.lazilyTransformingAstService) as ProcedureAst - const rangeAst = formula.args[0] as RowRangeAst - return AbsoluteRowRange.fromRowRangeAst(rangeAst, address) -} - -export const extractMatrixRange = (engine: HyperFormula, address: SimpleCellAddress): AbsoluteCellRange => { - const formula = (engine.addressMapping.getCell(address) as ArrayFormulaVertex).getFormula(engine.lazilyTransformingAstService) as ProcedureAst - const rangeAst = formula.args[0] as CellRangeAst - return AbsoluteCellRange.fromCellRange(rangeAst, address) -} - -export const expectReferenceToHaveRefError = (engine: HyperFormula, address: SimpleCellAddress) => { - const errorAst = (engine.addressMapping.getCell(address) as ScalarFormulaVertex).getFormula(engine.lazilyTransformingAstService) as ErrorAst - expect(errorAst.type).toEqual(AstNodeType.ERROR) - expect(errorAst.error).toEqualError(new CellError(ErrorType.REF)) -} - -export const expectFunctionToHaveRefError = (engine: HyperFormula, address: SimpleCellAddress) => { - const formula = (engine.addressMapping.getCell(address) as ScalarFormulaVertex).getFormula(engine.lazilyTransformingAstService) as ProcedureAst - const errorAst = formula.args.find((arg) => arg !== undefined && arg.type === AstNodeType.ERROR) as ErrorAst - expect(errorAst.type).toEqual(AstNodeType.ERROR) - expect(errorAst.error).toEqualError(new CellError(ErrorType.REF)) -} - -export const rangeAddr = (range: AbsoluteCellRange) => { - const start = simpleCellAddressToString(() => '', range.start, 0) - const end = simpleCellAddressToString(() => '', range.end, 0) - return `${start}:${end}` -} - -export const verifyRangesInSheet = (engine: HyperFormula, sheet: number, ranges: string[]) => { - const rangeVerticesInMapping = Array.from(engine.rangeMapping.rangesInSheet(sheet)) - .map((vertex) => rangeAddr(vertex.range)) - - const rangeVerticesInGraph = [ ...engine.graph.getNodes()].filter(vertex => vertex instanceof RangeVertex) - .map(vertex => rangeAddr((vertex as RangeVertex).range)) - - expectNoDuplicates(rangeVerticesInGraph) - expectNoDuplicates(rangeVerticesInMapping) - expectArrayWithSameContent(rangeVerticesInGraph, ranges) - expectArrayWithSameContent(rangeVerticesInMapping, ranges) -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const expectNoDuplicates = (array: any[]) => { - expect(new Set(array).size === array.length).toBe(true) -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const expectArrayWithSameContent = (actualArray: any[], expectedArray: any[]) => { - expect(actualArray.length).toBe(expectedArray.length) - expectedArray.forEach(expectedItem => expect(actualArray).toContainEqual(expectedItem)) - actualArray.forEach(actualItem => expect(expectedArray).toContainEqual(actualItem)) -} - -export const expectToBeCloseForComplex = (engine: HyperFormula, cell: string, expected: string, precision?: number) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const coerce = (arg: CellValue): complex => engine.evaluator.interpreter.arithmeticHelper.coerceScalarToComplex(arg) - const actualVal: complex = coerce(engine.getCellValue(adr(cell))) - const expectedVal: complex = coerce(expected) - expect(expectedVal[0]).toBeCloseTo(actualVal[0], precision) - expect(expectedVal[1]).toBeCloseTo(actualVal[1], precision) -} - -export const verifyValues = (engine: HyperFormula) => { - const serialization = engine.getAllSheetsSerialized() - const engine2 = HyperFormula.buildFromSheets(serialization) - expect(engine.getAllSheetsValues()).toEqual(engine2.getAllSheetsValues()) -} - -export const rowStart = (input: number, sheet: number = 0): SimpleCellAddress => { - return simpleCellAddress(sheet, 0, input - 1) -} - -export const rowEnd = (input: number, sheet: number = 0): SimpleCellAddress => { - return simpleCellAddress(sheet, Number.POSITIVE_INFINITY, input - 1) -} - -export const colStart = (input: string, sheet: number = 0): SimpleCellAddress => { - - const result = /^(\$?)([A-Za-z]+)/.exec(input)! - return simpleCellAddress(sheet, colNumber(result[2]), 0) -} - -export const colEnd = (input: string, sheet: number = 0): SimpleCellAddress => { - - const result = /^(\$?)([A-Za-z]+)/.exec(input)! - return simpleCellAddress(sheet, colNumber(result[2]), Number.POSITIVE_INFINITY) -} - -export const adr = (stringAddress: string, sheet: number = 0): SimpleCellAddress => { - - const result = /^(\$([A-Za-z0-9_]+)\.)?(\$?)([A-Za-z]+)(\$?)([0-9]+)$/.exec(stringAddress)! - const row = Number(result[6]) - 1 - return simpleCellAddress(sheet, colNumber(result[4]), row) -} - -const colNumber = (input: string): number => { - if (input.length === 1) { - return input.toUpperCase().charCodeAt(0) - 65 - } else { - return input.split('').reduce((currentColumn, nextLetter) => { - return currentColumn * 26 + (nextLetter.toUpperCase().charCodeAt(0) - 64) - }, 0) - 1 - } -} - -export function detailedError(errorType: ErrorType, message?: string, config?: Config): DetailedCellError { - config = new Config(config) - const error = new CellError(errorType, message) - return new DetailedCellError(error, config.translationPackage.getErrorTranslation(errorType)) -} - -export function noSpace(): DetailedCellError { - return detailedError(ErrorType.SPILL, ErrorMessage.NoSpaceForArrayResult) -} - -export function detailedErrorWithOrigin(errorType: ErrorType, address: string, message?: string, config?: Config): DetailedCellError { - config = new Config(config) - const error = new CellError(errorType, message) - return new DetailedCellError(error, config.translationPackage.getErrorTranslation(errorType), address) -} - -export const expectEngineToBeTheSameAs = (actual: HyperFormula, expected: HyperFormula) => { - const comparator = new EngineComparator(expected, actual) - comparator.compare() -} - -export function dateNumberToString(dateNumber: CellValue, config: Config): string | DetailedCellError { - if (dateNumber instanceof DetailedCellError) { - return dateNumber - } - const dateTimeHelper = new DateTimeHelper(config) - const dateString = defaultStringifyDateTime(dateTimeHelper.numberToSimpleDateTime(dateNumber as number), config.dateFormats[0]) - return dateString ?? '' -} - -export function timeNumberToString(timeNumber: CellValue, config: Config): string | DetailedCellError { - if (timeNumber instanceof DetailedCellError) { - return timeNumber - } - const dateTimeHelper = new DateTimeHelper(config) - const timeString = defaultStringifyDateTime(dateTimeHelper.numberToSimpleDateTime(timeNumber as number), 'hh:mm:ss.sss') - return timeString ?? '' -} - -export function unregisterAllLanguages() { - for (const langCode of HyperFormula.getRegisteredLanguagesCodes()) { - HyperFormula.unregisterLanguage(langCode) - } -} - -export function expectVerticesOfTypes(engine: HyperFormula, types: any[][], sheet: number = 0) { - for (let row = 0; row < types.length; ++row) { - for (let col = 0; col < types[row].length; ++col) { - const expectedType = types[row][col] - const cell = engine.dependencyGraph.getCell(simpleCellAddress(sheet, col, row)) - if (expectedType === undefined) { - expect(cell === undefined).toBe(true) - } else { - expect(cell instanceof types[row][col]).toBe(true) - } - } - } -} - -export function columnIndexToSheet(columnIndex: ColumnIndex, width: number, height: number, sheet: number = 0): any[][] { - const result: any[][] = [] - for (let col = 0; col < width; ++col) { - const columnMap = columnIndex.getColumnMap(sheet, col) - for (const [value, {index}] of columnMap.entries()) { - columnIndex.ensureRecentData(sheet, col, value) - for (const row of index) { - result[row] = result[row] ?? [] - if (result[row][col] !== undefined) { - throw new Error(`ColumnIndex ambiguity. Expected ${JSON.stringify(result[row][col])}, but found ${JSON.stringify(value)} at row ${JSON.stringify(row)}, column ${JSON.stringify(col)}`) - } - result[row][col] = value - } - } - } - return normalizeSheet(result, {width, height}) -} - -function normalizeSheet(sheet: RawCellContent[][], dimensions: SheetDimensions): any[][] { - return Array.from(sheet, row => { - if (row) { - row.length = dimensions.width - return Array.from(row, v => v || null) - } - return Array(dimensions.width).fill(null) as RawCellContent[] - }) -} - -export function expectColumnIndexToMatchSheet(expected: Sheet, engine: HyperFormula, sheetId: number = 0) { - const columnIndex = engine.columnSearch as ColumnIndex - expect(columnIndex).toBeInstanceOf(ColumnIndex) - const exportedColumnIndex = columnIndexToSheet(columnIndex, engine.getSheetDimensions(sheetId).width, sheetId) - const dimensions = engine.getSheetDimensions(0) - expectArrayWithSameContent(normalizeSheet(expected, dimensions), normalizeSheet(exportedColumnIndex, dimensions)) -} - -export function resetSpy(spy: any): void { - try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - spy.mockClear() // clears mock in Jest env - } catch { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access - spy.calls.reset() // clears mock in Jasmine env - } -} - -/** - * Helper method. Expects the cell value pointed by cellAddress to: - * - be a date and - * - when stringified, be equal to expectedDateString - */ -export function expectCellValueToEqualDate(engine: HyperFormula, cellAddress: SimpleCellAddress, expectedDateString: string) { - expect(dateNumberToString(engine.getCellValue(cellAddress), new Config())).toEqual(expectedDateString) -} - -/** - * Returns number of edges in graph - * - */ -export function graphEdgesCount(graph: Graph): number { - return (graph as any).nodesSparseArray.reduce((acc: number, node: T, id: number) => - node ? acc + ((graph as any).fixEdgesArrayForNode(id) as number[]).length : acc - , 0) -} - -export function graphReversedAdjacentNodes(graph: Graph, node: T): T[] { - const id = (graph as any).nodesIds.get(node) - - return (graph as any).nodesSparseArray.reduce((acc: number[], sourceNode: T, sourceId: number) => - sourceNode && (graph as any).edgesSparseArray[sourceId].includes(id) - ? [ ...acc, sourceId ] - : acc - , []).map((resultId: number) => (graph as any).nodesSparseArray[resultId]) -} diff --git a/test/unit/tsconfig.json b/test/unit/tsconfig.json deleted file mode 100644 index 7425e2cf3b..0000000000 --- a/test/unit/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - /* - * This file allows to debug jest tests locally and resolve custom matchers properly. - * Moving or renaming it can cause local development painful. - * It should not affect jasmine tests. - */ - "compilerOptions": { - "module": "commonjs", - "outDir": "../../test-jest", - /* Make sure proper types are used */ - "types": [ - "jest", - "node" - ] - }, - "extends": "../../tsconfig", - "include": [ - "../../../src", - "../unit" -, "../performance" ], - "exclude": [] -} diff --git a/test/unit/type-inference.spec.ts b/test/unit/type-inference.spec.ts deleted file mode 100644 index c153804e26..0000000000 --- a/test/unit/type-inference.spec.ts +++ /dev/null @@ -1,350 +0,0 @@ -import {HyperFormula} from '../../src' -import {CellValueDetailedType} from '../../src/Cell' -import {adr} from './testUtils' - -describe('arithmetic operations', () => { - it('addition should correctly infer types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1%', '1$', '01/01/1900', '12:00', '01/01/1900 12:00'], - ['=A1+A1', '=A1+B1', '=A1+C1', '=A1+D1', '=A1+E1', '=A1+F1'], - ['=B1+A1', '=B1+B1', '=B1+C1', '=B1+D1', '=B1+E1', '=B1+F1'], - ['=C1+A1', '=C1+B1', '=C1+C1', '=C1+D1', '=C1+E1', '=C1+F1'], - ['=D1+A1', '=D1+B1', '=D1+C1', '=D1+D1', '=D1+E1', '=D1+F1'], - ['=E1+A1', '=E1+B1', '=E1+C1', '=E1+D1', '=E1+E1', '=E1+F1'], - ['=F1+A1', '=F1+B1', '=F1+C1', '=F1+D1', '=F1+E1', '=F1+F1'], - ]) - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('C2'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D2'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E2'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F2'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('B3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('C3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('D3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('E3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('F3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('A4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('B4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('C4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('E4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('F4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('A5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('B5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('C5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('D5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E5'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('F5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('B6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('C6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('D6'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('E6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F6'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('B7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('C7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('D7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('F7'))).toBe(CellValueDetailedType.NUMBER_RAW) - }) - - it('subtraction should correctly infer types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1%', '1$', '01/01/1900', '12:00', '01/01/1900 12:00'], - ['=A1-A1', '=A1-B1', '=A1-C1', '=A1-D1', '=A1-E1', '=A1-F1'], - ['=B1-A1', '=B1-B1', '=B1-C1', '=B1-D1', '=B1-E1', '=B1-F1'], - ['=C1-A1', '=C1-B1', '=C1-C1', '=C1-D1', '=C1-E1', '=C1-F1'], - ['=D1-A1', '=D1-B1', '=D1-C1', '=D1-D1', '=D1-E1', '=D1-F1'], - ['=E1-A1', '=E1-B1', '=E1-C1', '=E1-D1', '=E1-E1', '=E1-F1'], - ['=F1-A1', '=F1-B1', '=F1-C1', '=F1-D1', '=F1-E1', '=F1-F1'], - ]) - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('C2'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D2'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E2'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F2'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('B3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('C3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('D3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('E3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('F3'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('A4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('B4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('C4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('E4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('F4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('A5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('B5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('C5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('D5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E5'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('F5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('B6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('C6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('D6'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('E6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F6'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('B7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('C7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('D7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('F7'))).toBe(CellValueDetailedType.NUMBER_RAW) - }) - - it('multiplication should correctly infer types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1%', '1$', '01/01/1900', '12:00', '01/01/1900 12:00'], - ['=A1*A1', '=A1*B1', '=A1*C1', '=A1*D1', '=A1*E1', '=A1*F1'], - ['=B1*A1', '=B1*B1', '=B1*C1', '=B1*D1', '=B1*E1', '=B1*F1'], - ['=C1*A1', '=C1*B1', '=C1*C1', '=C1*D1', '=C1*E1', '=C1*F1'], - ['=D1*A1', '=D1*B1', '=D1*C1', '=D1*D1', '=D1*E1', '=D1*F1'], - ['=E1*A1', '=E1*B1', '=E1*C1', '=E1*D1', '=E1*E1', '=E1*F1'], - ['=F1*A1', '=F1*B1', '=F1*C1', '=F1*D1', '=F1*E1', '=F1*F1'], - ]) - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('C2'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D2'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E2'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F2'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A3'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B3'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('C3'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D3'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E3'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F3'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('B4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('C4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('B5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('C5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('B6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('C6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('B7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('C7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F7'))).toBe(CellValueDetailedType.NUMBER_RAW) - }) - - it('division should correctly infer types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1%', '1$', '01/01/1900', '12:00', '01/01/1900 12:00'], - ['=A1/A1', '=A1/B1', '=A1/C1', '=A1/D1', '=A1/E1', '=A1/F1'], - ['=B1/A1', '=B1/B1', '=B1/C1', '=B1/D1', '=B1/E1', '=B1/F1'], - ['=C1/A1', '=C1/B1', '=C1/C1', '=C1/D1', '=C1/E1', '=C1/F1'], - ['=D1/A1', '=D1/B1', '=D1/C1', '=D1/D1', '=D1/E1', '=D1/F1'], - ['=E1/A1', '=E1/B1', '=E1/C1', '=E1/D1', '=E1/E1', '=E1/F1'], - ['=F1/A1', '=F1/B1', '=F1/C1', '=F1/D1', '=F1/E1', '=F1/F1'], - ]) - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('C2'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D2'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E2'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F2'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A3'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B3'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('C3'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D3'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E3'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F3'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('A4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('B4'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('C4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F4'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('B5'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('C5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F5'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('B6'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('C6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F6'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('A7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('B7'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - expect(engine.getCellValueDetailedType(adr('C7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('D7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('E7'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('F7'))).toBe(CellValueDetailedType.NUMBER_RAW) - }) - - it('percent should correctly infer types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1%', '1$', '01/01/1900', '12:00', '01/01/1900 12:00'], - ['=A1%', '=B1%', '=C1%', '=D1%', '=E1%', '=F1%'], - ]) - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('B2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('C2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('D2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('E2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('F2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - }) - - it('unary minus should correctly infer types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1%', '1$', '01/01/1900', '12:00', '01/01/1900 12:00'], - ['=-A1', '=-B1', '=-C1', '=-D1', '=-E1', '=-F1'], - ]) - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('C2'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D2'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E2'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F2'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - }) - - it('unary plus should correctly infer types', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '1%', '1$', '01/01/1900', '12:00', '01/01/1900 12:00'], - ['=+A1', '=+B1', '=+C1', '=+D1', '=+E1', '=+F1'], - ]) - expect(engine.getCellValueDetailedType(adr('A2'))).toBe(CellValueDetailedType.NUMBER_RAW) - expect(engine.getCellValueDetailedType(adr('B2'))).toBe(CellValueDetailedType.NUMBER_PERCENT) - expect(engine.getCellValueDetailedType(adr('C2'))).toBe(CellValueDetailedType.NUMBER_CURRENCY) - expect(engine.getCellValueDetailedType(adr('D2'))).toBe(CellValueDetailedType.NUMBER_DATE) - expect(engine.getCellValueDetailedType(adr('E2'))).toBe(CellValueDetailedType.NUMBER_TIME) - expect(engine.getCellValueDetailedType(adr('F2'))).toBe(CellValueDetailedType.NUMBER_DATETIME) - }) -}) - -describe('formatting info', () => { - it('should be preserved by unary minus', () => { - const engine = HyperFormula.buildFromArray([ - ['1$', '1', '1PLN'], - ['=-A1', '=-B1', '=C1'], - ], {currencySymbol: ['$', 'PLN']}) - expect(engine.getCellValueFormat(adr('A2'))).toBe('$') - expect(engine.getCellValueFormat(adr('B2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('C2'))).toBe('PLN') - }) - - it('should be preserved by unary plus', () => { - const engine = HyperFormula.buildFromArray([ - ['1$', '1', '1PLN'], - ['=+A1', '=+B1', '=+C1'], - ], {currencySymbol: ['$', 'PLN']}) - expect(engine.getCellValueFormat(adr('A2'))).toBe('$') - expect(engine.getCellValueFormat(adr('B2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('C2'))).toBe('PLN') - }) - - it('should be preserved by addition', () => { - const engine = HyperFormula.buildFromArray([ - ['1$', '1', '1PLN'], - ['=A1+A1', '=A1+B1', '=A1+C1'], - ['=B1+A1', '=B1+B1', '=B1+C1'], - ['=C1+A1', '=C1+B1', '=C1+C1'], - ], {currencySymbol: ['$', 'PLN']}) - expect(engine.getCellValueFormat(adr('A2'))).toBe('$') - expect(engine.getCellValueFormat(adr('B2'))).toBe('$') - expect(engine.getCellValueFormat(adr('C2'))).toBe('$') - expect(engine.getCellValueFormat(adr('A3'))).toBe('$') - expect(engine.getCellValueFormat(adr('B3'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('C3'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('A4'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('B4'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('C4'))).toBe('PLN') - }) - - it('should be preserved by subtraction', () => { - const engine = HyperFormula.buildFromArray([ - ['1$', '1', '1PLN'], - ['=A1-A1', '=A1-B1', '=A1-C1'], - ['=B1-A1', '=B1-B1', '=B1-C1'], - ['=C1-A1', '=C1-B1', '=C1-C1'], - ], {currencySymbol: ['$', 'PLN']}) - expect(engine.getCellValueFormat(adr('A2'))).toBe('$') - expect(engine.getCellValueFormat(adr('B2'))).toBe('$') - expect(engine.getCellValueFormat(adr('C2'))).toBe('$') - expect(engine.getCellValueFormat(adr('A3'))).toBe('$') - expect(engine.getCellValueFormat(adr('B3'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('C3'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('A4'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('B4'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('C4'))).toBe('PLN') - }) - - it('should be preserved by multiplication', () => { - const engine = HyperFormula.buildFromArray([ - ['1$', '1', '1PLN'], - ['=A1*A1', '=A1*B1', '=A1*C1'], - ['=B1*A1', '=B1*B1', '=B1*C1'], - ['=C1*A1', '=C1*B1', '=C1*C1'], - ], {currencySymbol: ['$', 'PLN']}) - expect(engine.getCellValueFormat(adr('A2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('B2'))).toBe('$') - expect(engine.getCellValueFormat(adr('C2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('A3'))).toBe('$') - expect(engine.getCellValueFormat(adr('B3'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('C3'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('A4'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('B4'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('C4'))).toBe(undefined) - }) - - it('should be preserved by division', () => { - const engine = HyperFormula.buildFromArray([ - ['1$', '1', '1PLN'], - ['=A1/A1', '=A1/B1', '=A1/C1'], - ['=B1/A1', '=B1/B1', '=B1/C1'], - ['=C1/A1', '=C1/B1', '=C1/C1'], - ], {currencySymbol: ['$', 'PLN']}) - expect(engine.getCellValueFormat(adr('A2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('B2'))).toBe('$') - expect(engine.getCellValueFormat(adr('C2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('A3'))).toBe('$') - expect(engine.getCellValueFormat(adr('B3'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('C3'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('A4'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('B4'))).toBe('PLN') - expect(engine.getCellValueFormat(adr('C4'))).toBe(undefined) - }) -}) - -describe('Datetime formatting', () => { - it('should be correctly inferred by addition', () => { - const engine = HyperFormula.buildFromArray([ - ['01/01/1900', '12:00', '01/01/1900 12:00'], - ['=A1+A1', '=A1+B1', '=A1+C1'], - ['=B1+A1', '=B1+B1', '=B1+C1'], - ['=C1+A1', '=C1+B1', '=C1+C1'], - ]) - expect(engine.getCellValueFormat(adr('A2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('B2'))).toBe('DD/MM/YYYY hh:mm') - expect(engine.getCellValueFormat(adr('C2'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('A3'))).toBe('DD/MM/YYYY hh:mm') - expect(engine.getCellValueFormat(adr('B3'))).toBe('hh:mm') - expect(engine.getCellValueFormat(adr('C3'))).toBe('DD/MM/YYYY hh:mm') - expect(engine.getCellValueFormat(adr('A4'))).toBe(undefined) - expect(engine.getCellValueFormat(adr('B4'))).toBe('DD/MM/YYYY hh:mm') - expect(engine.getCellValueFormat(adr('C4'))).toBe(undefined) - }) -}) diff --git a/test/unit/undo-redo.spec.ts b/test/unit/undo-redo.spec.ts deleted file mode 100644 index 14927f1534..0000000000 --- a/test/unit/undo-redo.spec.ts +++ /dev/null @@ -1,2575 +0,0 @@ -/* eslint-disable jest/expect-expect */ -import {ErrorType, HyperFormula, NoOperationToRedoError, NoOperationToUndoError} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {ErrorMessage} from '../../src/error-message' -import {adr, detailedError, expectEngineToBeTheSameAs} from './testUtils' -import {UndoRedo, AddSheetUndoEntry} from '../../src/UndoRedo' -import {Config} from '../../src/Config' -import {DependencyGraph} from '../../src/DependencyGraph' -import {Statistics} from '../../src/statistics' -import {FunctionRegistry} from '../../src/interpreter/FunctionRegistry' -import {LazilyTransformingAstService} from '../../src/LazilyTransformingAstService' -import {NamedExpressions} from '../../src/NamedExpressions' -import {Operations} from '../../src/Operations' -import {buildColumnSearchStrategy} from '../../src/Lookup/SearchStrategy' -import {CellContentParser} from '../../src/CellContentParser' -import {DateTimeHelper} from '../../src/DateTimeHelper' -import {NumberLiteralHelper} from '../../src/NumberLiteralHelper' -import {ParserWithCaching} from '../../src/parser' -import {ArraySizePredictor} from '../../src/ArraySize' - -describe('Undo - removing rows', () => { - it('works for empty row', () => { - const sheet = [ - ['1'], - [null], // remove - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('works for simple values', () => { - const sheet = [ - ['1'], - ['2'], // remove - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('works with formula in removed row', () => { - const sheet = [ - ['1'], - ['=SUM(A1)'], // remove - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores dependent cell formulas', () => { - const sheet = [ - ['=A2'], - ['42'], // remove - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('formulas are built correctly when there was a pause in computation', () => { - const sheet = [ - ['=A2'], - ['42'], // remove - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.suspendEvaluation() - engine.removeRows(0, [1, 1]) - - engine.undo() - engine.resumeEvaluation() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores ranges when removing rows', () => { - const sheet = [ - ['=SUM(A2:A3)'], - ['2'], // remove - ['3'], // remove - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1, 2]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('dummy operation removeRows should also be undoable', () => { - const sheet = [ - ['1'] - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1000, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('works for more removal segments', () => { - const sheet = [ - ['1'], - ['2'], - ['3'], - ['4'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1, 1], [3, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('Undo - adding rows', () => { - it('restores original state after adding single row', () => { - const sheet = [ - ['1'], // add after that - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.addRows(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('dummy operation addRows should also be undoable', () => { - const sheet = [ - ['1'] - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.addRows(0, [1000, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('works for more addition segments', () => { - const sheet = [ - ['1'], - ['2'], - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.addRows(0, [1, 1], [2, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('Undo - moving rows', () => { - it('restores original row order after move', () => { - const sheet = [ - [0], [1], [2], [3], [4], [5], [6], [7], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.moveRows(0, 1, 3, 7) - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores original row order when moving rows backward', () => { - const sheet = [ - [0], [1], [2], [3], [4], [5], [6], [7], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.moveRows(0, 4, 3, 2) - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores range formula after moving rows forward', () => { - const engine = HyperFormula.buildFromArray([ - [1, null], - [2, '=SUM(A1:A2)'], - ]) - engine.moveRows(0, 1, 1, 3) - engine.undo() - - expect(engine.getCellFormula(adr('B2'))).toBe('=SUM(A1:A2)') - }) - - it('should restore range when moving other way', () => { - const engine = HyperFormula.buildFromArray([ - [1, null], - [2, '=SUM(A1:A2)'], - ]) - - engine.moveRows(0, 2, 1, 1) - engine.undo() - - expect(engine.getCellFormula(adr('B2'))).toBe('=SUM(A1:A2)') - }) -}) - -describe('Undo - moving columns', () => { - it('restores original column order after move', () => { - const sheet = [ - [0, 1, 2, 3, 4, 5, 6, 7], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.moveColumns(0, 1, 3, 7) - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores original column order when moving columns backward', () => { - const sheet = [ - [0, 1, 2, 3, 4, 5, 6, 7], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.moveColumns(0, 4, 3, 2) - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores range formula after moving columns forward', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [null, '=SUM(A1:B1)'], - ]) - engine.moveColumns(0, 1, 1, 3) - engine.undo() - - expect(engine.getCellFormula(adr('B2'))).toBe('=SUM(A1:B1)') - }) - - it('should restore range when moving to left', () => { - const engine = HyperFormula.buildFromArray([ - [1, 2], - [null, '=SUM(A1:B1)'], - ]) - - engine.moveColumns(0, 2, 1, 1) - engine.undo() - - expect(engine.getCellFormula(adr('B2'))).toBe('=SUM(A1:B1)') - }) -}) - -describe('Undo - adding columns', () => { - it('restores original state after adding single column', () => { - const sheet = [ - ['1', /* */ '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.addColumns(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('dummy operation addColumns should also be undoable', () => { - const sheet = [ - ['1'] - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.addColumns(0, [1000, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores state after adding multiple column segments', () => { - const sheet = [ - ['1', '2', '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.addColumns(0, [1, 1], [2, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('Undo - removing columns', () => { - it('works for empty column', () => { - const sheet = [ - ['1', null, '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeColumns(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores column with simple values', () => { - const sheet = [ - ['1', '2', '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeColumns(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('works with formula in removed columns', () => { - const sheet = [ - ['1', '=SUM(A1)', '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeColumns(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores dependent cell formulas after column removal', () => { - const sheet = [ - ['=A2', '42', '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeColumns(0, [1, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('builds formulas correctly with suspended evaluation during column removal', () => { - const sheet = [ - ['=A2', '42', '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.suspendEvaluation() - engine.removeColumns(0, [1, 1]) - - engine.undo() - engine.resumeEvaluation() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores ranges when removing columns', () => { - const sheet = [ - ['=SUM(B1:C1)', '2', '3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeColumns(0, [1, 2]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('dummy operation removeColumns should also be undoable', () => { - const sheet = [ - ['1'] - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeColumns(0, [1000, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores state after removing multiple column segments', () => { - const sheet = [ - ['1', '2', '3', '4'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeColumns(0, [1, 1], [3, 1]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('Undo - removing sheet', () => { - it('works for empty sheet', () => { - const engine = HyperFormula.buildFromArray([]) - engine.removeSheet(0) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([])) - }) - - it('works with restoring simple values', () => { - const sheet = [ - ['1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeSheet(0) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('works with restoring formulas', () => { - const sheet = [ - ['=42'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeSheet(0) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores cross-sheet formula dependencies after sheet removal', () => { - const sheets = { - Sheet1: [['=Sheet2!A1']], - Sheet2: [['42']], - } - const engine = HyperFormula.buildFromSheets(sheets) - engine.removeSheet(1) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(sheets)) - }) - - it('builds formulas correctly with suspended evaluation during sheet removal', () => { - const sheets = { - Sheet1: [['=Sheet2!A1']], - Sheet2: [['42']], - } - const engine = HyperFormula.buildFromSheets(sheets) - engine.suspendEvaluation() - engine.removeSheet(1) - - engine.undo() - engine.resumeEvaluation() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(sheets)) - }) - - it('restores sheet correctly after multiple undo/redo cycles', () => { - const sheets = { - Sheet1: [['1', '2']], - Sheet2: [['3', '4']], - } - const engine = HyperFormula.buildFromSheets(sheets) - engine.removeSheet(1) - - engine.undo() - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(sheets)) - - engine.redo() - - expect(engine.getSheetNames()).toEqual(['Sheet1']) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(sheets)) - - engine.redo() - - expect(engine.getSheetNames()).toEqual(['Sheet1']) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(sheets)) - - engine.redo() - - expect(engine.getSheetNames()).toEqual(['Sheet1']) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(sheets)) - }) - - it('restores sheet and cross-sheet references after row removal', () => { - const sheets = { - Sheet1: [['1'], ['2'], ['=Sheet2!A1']], - Sheet2: [['42']], - } - const engine = HyperFormula.buildFromSheets(sheets) - engine.removeSheet(1) - engine.undo() - - expect(engine.getSheetNames()).toEqual(['Sheet1', 'Sheet2']) - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('A2'))).toBe(2) - expect(engine.getCellValue(adr('A3'))).toBe(42) - expect(engine.getCellValue(adr('A1', 1))).toBe(42) - }) - - it('restores scoped named expressions', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['=MyName']], - Sheet2: [['1']], - }) - engine.addNamedExpression('MyName', '=42', 0) - engine.removeSheet(0) - engine.undo() - - expect(engine.getCellValue(adr('A1'))).toBe(42) - }) -}) - -describe('Undo - renaming sheet', () => { - it('undo previous operation if name not changes', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.setCellContents(adr('A1'), [[2]]) - engine.renameSheet(0, 'Sheet1') - - engine.undo() - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getSheetName(0)).toBe('Sheet1') - }) - - it('undo rename sheet', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'Foo') - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - }) - - it('undo rename with case change only', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'SHEET1') - - expect(engine.getSheetName(0)).toBe('SHEET1') - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - }) - - it('undo rename preserves cell values', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[42], ['=A1*2']]}) - engine.renameSheet(0, 'NewName') - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - expect(engine.getCellValue(adr('A1'))).toBe(42) - expect(engine.getCellValue(adr('A2'))).toBe(84) - }) - - it('undo rename with suspended evaluation', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.suspendEvaluation() - engine.renameSheet(0, 'Foo') - engine.undo() - engine.resumeEvaluation() - - expect(engine.getSheetName(0)).toBe('Sheet1') - }) - - it('undo rename that merged with placeholder sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=OldName!A1', '=NewName!A1']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(42) - - engine.undo() - - expect(engine.getSheetName(oldNameId)).toBe('OldName') - expect(engine.getCellFormula(adr('A1', sheet1Id))).toBe('=OldName!A1') - expect(engine.getCellFormula(adr('B1', sheet1Id))).toBe('=NewName!A1') - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - }) - - it('undo rename with range reference updates formula (merged with placeholder sheet)', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SUM(OldName!A1:B2)', '=SUM(NewName!A1:B2)']], - 'OldName': [[10, 20], [30, 40]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getCellFormula(adr('A1', sheet1Id))).toBe('=SUM(NewName!A1:B2)') - expect(engine.getCellFormula(adr('B1', sheet1Id))).toBe('=SUM(NewName!A1:B2)') - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(100) - - engine.undo() - - expect(engine.getCellFormula(adr('A1', sheet1Id))).toBe('=SUM(OldName!A1:B2)') - expect(engine.getCellFormula(adr('B1', sheet1Id))).toBe('=SUM(NewName!A1:B2)') - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - }) - - it('restores the dependency graph structure on undo', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [ - ['=OldName!A1', '=NewName!A1', '=SUM(OldName!A1:B2)', '=SUM(NewName!A1:B2)'], - ['=A1*2', '=B1+10', '=C1+A1', '=D1+B1'], - ], - 'OldName': [[1, 2], [3, 4]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(10) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('B2', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('C2', sheet1Id))).toBe(11) - expect(engine.getCellValue(adr('D2', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(10) - expect(engine.getCellValue(adr('D1', sheet1Id))).toBe(10) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('B2', sheet1Id))).toBe(11) - expect(engine.getCellValue(adr('C2', sheet1Id))).toBe(11) - expect(engine.getCellValue(adr('D2', sheet1Id))).toBe(11) - - engine.undo() - - expect(engine.getCellFormula(adr('A1', sheet1Id))).toBe('=OldName!A1') - expect(engine.getCellFormula(adr('B1', sheet1Id))).toBe('=NewName!A1') - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(10) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('B2', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('C2', sheet1Id))).toBe(11) - expect(engine.getCellValue(adr('D2', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.setCellContents(adr('A1', oldNameId), 100) - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('C1', sheet1Id))).toBe(109) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(200) - expect(engine.getCellValue(adr('C2', sheet1Id))).toBe(209) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('D1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('B2', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getCellValue(adr('D2', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - }) - - it('multiple undo/redo cycles for rename', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'Renamed') - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - - engine.redo() - - expect(engine.getSheetName(0)).toBe('Renamed') - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - - engine.redo() - - expect(engine.getSheetName(0)).toBe('Renamed') - }) - - it('undo multiple sequential renames', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'Name1') - engine.renameSheet(0, 'Name2') - engine.renameSheet(0, 'Name3') - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Name2') - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Name1') - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - }) - - it('undo rename combined with cell content changes', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.setCellContents(adr('A1'), 10) - engine.renameSheet(0, 'NewName') - engine.setCellContents(adr('A1'), 100) - engine.undo() - - expect(engine.getCellValue(adr('A1'))).toBe(10) - expect(engine.getSheetName(0)).toBe('NewName') - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - - engine.undo() - - expect(engine.getCellValue(adr('A1'))).toBe(1) - }) - - it('undo rename in batch mode', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]], 'Sheet2': [[2]]}) - engine.batch(() => { - engine.renameSheet(0, 'NewName1') - engine.renameSheet(1, 'NewName2') - }) - - engine.undo() - - expect(engine.getSheetName(0)).toBe('Sheet1') - expect(engine.getSheetName(1)).toBe('Sheet2') - }) - - it('undo rename with chained dependencies across sheets', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=Sheet2!A1+2']], - 'Sheet2': [['=OldName!A1*2']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const sheet2Id = engine.getSheetId('Sheet2')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet2Id))).toBe(84) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(86) - - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getCellFormula(adr('A1', sheet2Id))).toBe('=NewName!A1*2') - - engine.undo() - - expect(engine.getCellFormula(adr('A1', sheet2Id))).toBe('=OldName!A1*2') - expect(engine.getCellValue(adr('A1', sheet2Id))).toBe(84) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(86) - }) - - it('undo rename with named expressions', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=MyValue']], - 'OldName': [[99]], - }, {}, [ - { name: 'MyValue', expression: '=OldName!$A$1' } - ]) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(99) - - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getNamedExpressionFormula('MyValue')).toBe('=NewName!$A$1') - - engine.undo() - - expect(engine.getNamedExpressionFormula('MyValue')).toBe('=OldName!$A$1') - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(99) - }) - - it('undo rename after row removal', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [[1], [2], ['=OldName!A1']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - engine.removeRows(sheet1Id, [0, 1]) - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(42) - expect(engine.getCellFormula(adr('A2', sheet1Id))).toBe('=NewName!A1') - - engine.undo() - - expect(engine.getCellFormula(adr('A2', sheet1Id))).toBe('=OldName!A1') - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(42) - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(1) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(2) - expect(engine.getCellValue(adr('A3', sheet1Id))).toBe(42) - }) - - it('undo rename sheet that merged with placeholder restores placeholder', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=PlaceholderName!A1']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'PlaceholderName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getSheetName(oldNameId)).toBe('PlaceholderName') - - engine.undo() - - expect(engine.getSheetName(oldNameId)).toBe('OldName') - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - }) - - it('redo rename sheet that merged with placeholder works correctly', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=PlaceholderName!A1']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'PlaceholderName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getSheetName(oldNameId)).toBe('PlaceholderName') - }) - - it('multiple undo/redo cycles with placeholder sheet merge', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=GhostSheet!A1']], - 'RealSheet': [[100]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const realSheetId = engine.getSheetId('RealSheet')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(realSheetId, 'GhostSheet') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getSheetName(realSheetId)).toBe('RealSheet') - - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getSheetName(realSheetId)).toBe('GhostSheet') - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getSheetName(realSheetId)).toBe('RealSheet') - - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getSheetName(realSheetId)).toBe('GhostSheet') - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - }) - - it('undo rename with range reference to placeholder sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SUM(PlaceholderName!A1:B2)']], - 'OldName': [[1, 2], [3, 4]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'PlaceholderName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(10) - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - expect(engine.getSheetName(oldNameId)).toBe('OldName') - - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(10) - }) -}) - -describe('Undo - setting cell content', () => { - it('restores simple numeric values', () => { - const sheet = [ - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.setCellContents(adr('A1'), '100') - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores empty cell state', () => { - const sheet = [ - [null], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.setCellContents(adr('A1'), '100') - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores formula cell content', () => { - const sheet = [ - ['=42'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.setCellContents(adr('A1'), '100') - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('undoes multiple cell contents as one operation', () => { - const sheet = [ - ['3', '4'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.setCellContents(adr('A1'), [['5', '6']]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('Undo - adding sheet', () => { - it('removes named sheet on undo', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addSheet('SomeSheet') - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([])) - }) - - it('removes auto-generated sheet on undo', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addSheet() - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([])) - }) - - it('restores cross-sheet reference error after undo', () => { - const engine = HyperFormula.buildFromArray([['=NewSheet!A1']]) - engine.addSheet('NewSheet') - engine.setCellContents({sheet: 1, col: 0, row: 0}, '42') - - expect(engine.getCellValue(adr('A1'))).toBe(42) - expect(engine.getCellValue(adr('A1', 1))).toBe(42) - - engine.undo() - engine.undo() - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - }) - - it('builds formulas correctly with suspended evaluation during sheet addition', () => { - const engine = HyperFormula.buildFromArray([['=NewSheet!A1']]) - engine.suspendEvaluation() - engine.addSheet('NewSheet') - engine.setCellContents({sheet: 1, col: 0, row: 0}, '42') - - engine.undo() - engine.undo() - engine.resumeEvaluation() - - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - }) -}) - -describe('Undo - clearing sheet', () => { - it('handles undo on already empty sheet', () => { - const engine = HyperFormula.buildFromArray([]) - engine.clearSheet(0) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray([])) - }) - - it('restores simple values after clearing', () => { - const sheet = [ - ['1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.clearSheet(0) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores formulas after clearing', () => { - const sheet = [ - ['=42'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.clearSheet(0) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('Undo - setting sheet contents', () => { - it('restores original sheet content', () => { - const sheet = [['13']] - const engine = HyperFormula.buildFromArray(sheet) - engine.setSheetContent(0, [['42']]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('also clears sheet when undoing', () => { - const sheet = [ - ['1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.setSheetContent(0, [['42', '43']]) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('Undo - moving cells', () => { - it('restores cell to original position', () => { - const sheet = [ - ['foo'], - [null], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores overwritten data at target location', () => { - const sheet = [ - ['foo'], - ['42'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('restores dependent cell formulas after cell move', () => { - const sheet = [ - ['=A2'], - ['42'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('builds formulas correctly with suspended evaluation during cell move', () => { - const sheet = [ - ['=A2'], - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.suspendEvaluation() - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - engine.undo() - engine.resumeEvaluation() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('removes global named expression promoted during move', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [], - 'Sheet2': [] - }) - engine.addNamedExpression('foo', 'bar', 0) - engine.setCellContents(adr('A1'), '=foo') - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A1', 1)) - - engine.undo() - - expect(engine.getNamedExpressionValue('foo')).toBeUndefined() - }) - - it('remove global named expression even if it was added after formula', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=foo']], - 'Sheet2': [] - }) - engine.addNamedExpression('foo', 'bar', 0) - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A1', 1)) - - engine.undo() - - expect(engine.getNamedExpressionValue('foo', 0)).toBe('bar') - expect(engine.getNamedExpressionValue('foo')).toBeUndefined() - }) -}) - -describe('Undo - cut-paste', () => { - it('restores source and target cells after cut-paste', () => { - const sheet = [ - ['foo'], - ['bar'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('does not roll back clipboard on undo', () => { - const sheet = [ - ['foo'], - ['bar'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - engine.undo() - - expect(engine.isClipboardEmpty()).toBe(true) - }) - - it('removes global named expression promoted during cut-paste', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [], - 'Sheet2': [] - }) - engine.addNamedExpression('foo', 'bar', 0) - engine.setCellContents(adr('A1'), '=foo') - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A1', 1)) - - engine.undo() - - expect(engine.getNamedExpressionValue('foo', 0)).toBe('bar') - expect(engine.getNamedExpressionValue('foo')).toBeUndefined() - }) -}) - -describe('Undo - copy-paste', () => { - it('restores original content after copy-paste', () => { - const sheet = [ - ['foo'], - ['bar'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('removes global named expression promoted during copy-paste', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [], - 'Sheet2': [] - }) - engine.addNamedExpression('foo', 'bar', 0) - engine.setCellContents(adr('A1'), '=foo') - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A1', 1)) - - engine.undo() - - expect(engine.getNamedExpressionValue('foo', 0)).toBe('bar') - expect(engine.getNamedExpressionValue('foo')).toBeUndefined() - }) -}) - -describe('Undo - add named expression', () => { - it('removes named expression and restores error', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo'] - ]) - - engine.addNamedExpression('foo', 'foo') - - engine.undo() - - expect(engine.listNamedExpressions().length).toBe(0) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('foo'))) - }) -}) - -describe('Undo - remove named expression', () => { - it('restores removed named expression', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo'] - ]) - - engine.addNamedExpression('foo', 'foo') - engine.removeNamedExpression('foo') - - engine.undo() - - expect(engine.listNamedExpressions().length).toBe(1) - expect(engine.getCellValue(adr('A1'))).toBe('foo') - }) -}) - -describe('Undo - change named expression', () => { - it('restores original expression value', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo'] - ]) - - engine.addNamedExpression('foo', 'foo') - engine.changeNamedExpression('foo', 'bar') - - engine.undo() - - expect(engine.listNamedExpressions().length).toBe(1) - expect(engine.getCellValue(adr('A1'))).toBe('foo') - }) -}) - -describe('Undo', () => { - it('throws error when undo stack is empty', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => { - engine.undo() - }).toThrow(new NoOperationToUndoError()) - }) - - it('undo recomputes and return changes', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '=A1'], - ]) - engine.setCellContents(adr('A1'), '100') - - const changes = engine.undo() - - expect(engine.getCellValue(adr('B1'))).toBe(3) - expect(changes.length).toBe(2) - }) - - it('operations in batch mode are one undo', () => { - const sheet = [ - ['1', '2'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.batch(() => { - engine.setCellContents(adr('A1'), '10') - engine.setCellContents(adr('A2'), '20') - }) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - - expect(engine.isThereSomethingToUndo()).toBe(false) - }) - - it('operations in batch mode are undone in correct order', () => { - const sheet = [ - ['1'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.batch(() => { - engine.setCellContents(adr('A1'), '10') - engine.removeRows(0, [0, 1]) - }) - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) - - it('keeps elements within limit', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ], {undoLimit: 3}) - engine.setCellContents(adr('A1'), '2') - engine.setCellContents(adr('A1'), '3') - engine.setCellContents(adr('A1'), '4') - engine.setCellContents(adr('A1'), '5') - - engine.undo() - engine.undo() - engine.undo() - - expect(engine.isThereSomethingToUndo()).toBe(false) - }) - - it('undo limit works with infinity', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ], {undoLimit: Infinity}) - engine.setCellContents(adr('A1'), '2') - engine.setCellContents(adr('A1'), '3') - engine.setCellContents(adr('A1'), '4') - - expect(engine.isThereSomethingToUndo()).toBe(true) - }) - - it('restore AST after irreversible operation', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('E1'), '=SUM(A1:C1)') - engine.addColumns(0, [3, 1]) - engine.removeColumns(0, [0, 1]) - - expect(() => engine.undo()).not.toThrowError() - expect(engine.getCellFormula(adr('F1'))).toBe('=SUM(A1:C1)') - }) -}) - -describe('UndoRedo', () => { - it('redo operation is pushed back on undo stack (undo-redo-undo)', () => { - const sheet = [ - ['1'], - ['2', '=A1'], // remove - ['3'], - ] - const engine = HyperFormula.buildFromArray(sheet) - engine.removeRows(0, [1, 1]) - engine.undo() - engine.redo() - - engine.undo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromArray(sheet)) - }) -}) - -describe('UndoRedo - #isThereSomethingToUndo', () => { - it('returns false when undo stack is empty', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.isThereSomethingToUndo()).toBe(false) - }) - - it('when there is some operation to undo', () => { - const engine = HyperFormula.buildFromArray([]) - engine.removeRows(0, [1, 1]) - - expect(engine.isThereSomethingToUndo()).toBe(true) - }) - - it('when the undo stack has been cleared', () => { - const engine = HyperFormula.buildFromArray([]) - engine.removeRows(0, [1, 1]) - - expect(engine.isThereSomethingToUndo()).toBe(true) - engine.clearUndoStack() - - expect(engine.isThereSomethingToUndo()).toBe(false) - }) -}) - -describe('UndoRedo - #isThereSomethingToRedo', () => { - it('when there is no operation to redo', () => { - const engine = HyperFormula.buildEmpty() - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) - - it('when there is some operation to redo', () => { - const engine = HyperFormula.buildFromArray([]) - engine.removeRows(0, [1, 1]) - engine.undo() - - expect(engine.isThereSomethingToRedo()).toBe(true) - }) - - it('when the redo stack has been cleared', () => { - const engine = HyperFormula.buildFromArray([]) - engine.removeRows(0, [1, 1]) - engine.undo() - - expect(engine.isThereSomethingToRedo()).toBe(true) - engine.clearRedoStack() - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('UndoRedo - at the Operations layer', () => { - let undoRedo: UndoRedo - - beforeEach(() => { - const config = new Config() - const stats = new Statistics() - const namedExpressions = new NamedExpressions() - const functionRegistry = new FunctionRegistry(config) - const lazilyTransformingAstService = new LazilyTransformingAstService(stats) - const dependencyGraph = DependencyGraph.buildEmpty(lazilyTransformingAstService, config, functionRegistry, namedExpressions, stats) - const columnSearch = buildColumnSearchStrategy(dependencyGraph, config, stats) - const dateTimeHelper = new DateTimeHelper(config) - const numberLiteralHelper = new NumberLiteralHelper(config) - const cellContentParser = new CellContentParser(config, dateTimeHelper, numberLiteralHelper) - const parser = new ParserWithCaching( - config, - functionRegistry, - dependencyGraph.sheetReferenceRegistrar.ensureSheetRegistered.bind(dependencyGraph.sheetReferenceRegistrar) - ) - const arraySizePredictor = new ArraySizePredictor(config, functionRegistry) - const operations = new Operations(config, dependencyGraph, columnSearch, cellContentParser, parser, stats, lazilyTransformingAstService, namedExpressions, arraySizePredictor) - undoRedo = new UndoRedo(config, operations) - }) - - it('commitBatchMode should throw when a batch is not in progress', () => { - expect(() => { - undoRedo.commitBatchMode() - }).toThrowError("Batch mode wasn't started") - }) - - it('clearUndoStack should clear out all undo entries', () => { - expect(undoRedo.isUndoStackEmpty()).toBe(true) - undoRedo.saveOperation(new AddSheetUndoEntry('Sheet 1', 1)) - undoRedo.saveOperation(new AddSheetUndoEntry('Sheet 2', 2)) - - expect(undoRedo.isUndoStackEmpty()).toBe(false) - - undoRedo.clearUndoStack() - - expect(undoRedo.isUndoStackEmpty()).toBe(true) - }) - - it('undo should throw when there is nothing on the undo stack', () => { - expect(() => { - undoRedo.undo() - }).toThrowError('Attempted to undo without operation on stack') - }) - - it('redo should throw when there is nothing on the redo stack', () => { - expect(() => { - undoRedo.redo() - }).toThrowError('Attempted to redo without operation on stack') - }) -}) - -describe('Redo - removing rows', () => { - it('re-removes empty row after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - [null], // remove - ['3'], - ]) - engine.removeRows(0, [1, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-removes row with values and formulas after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2', '=A1'], // remove - ['3'], - ]) - engine.removeRows(0, [1, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-removes multiple row segments after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ['4'], - ]) - engine.removeRows(0, [1, 1], [3, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('dummy removeRows operation is redoable', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - engine.removeRows(0, [1000, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('removeRows clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.removeRows(0, [1000, 1]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - adding rows', () => { - it('re-adds row after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], // add after that - ['3'], - ]) - engine.addRows(0, [1, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('dummy addRows operation is redoable', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - engine.addRows(0, [1000, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-adds multiple row segments after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], - ]) - engine.addRows(0, [1, 1], [2, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('addRows clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.addRows(0, [1000, 1]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - moving rows', () => { - it('re-applies row move after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ['2'], - ['3'], // move first row before this one - ]) - engine.moveRows(0, 0, 1, 2) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('moveRows clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.moveRows(0, 0, 1, 2) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - moving columns', () => { - it('re-applies column move after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ]) - engine.moveColumns(0, 0, 1, 2) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('moveColumns clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.moveColumns(0, 0, 1, 2) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - moving cells', () => { - it('re-applies cell move after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['42'], - ['45'], - ]) - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('moveCells clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - setting cell content', () => { - it('re-applies simple value change after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['3'], - ]) - engine.setCellContents(adr('A1'), '100') - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-applies cell clearing after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['3'], - ]) - engine.setCellContents(adr('A1'), null) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-applies formula value change after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['3'], - ]) - engine.setCellContents(adr('A1'), '=42') - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('redoes multiple cell contents as one operation', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '4'], - ]) - engine.setCellContents(adr('A1'), [['5', '6']]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('setCellContents clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.setCellContents(adr('A1'), 78) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - removing sheet', () => { - it('re-removes sheet after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - engine.removeSheet(0) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('removeSheet clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.removeSheet(0) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) - - it('redo with cross-sheet formula dependencies', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['=Sheet2!A1']], - Sheet2: [['42']], - }) - engine.removeSheet(1) - engine.undo() - - expect(engine.getSheetNames()).toEqual(['Sheet1', 'Sheet2']) - - engine.redo() - - expect(engine.getSheetNames()).toEqual(['Sheet1']) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - }) - - it('removes sheet correctly after multiple undo/redo cycles', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['1']], - Sheet2: [['2']], - }) - engine.removeSheet(1) - - engine.undo() - engine.redo() - engine.undo() - engine.redo() - engine.undo() - engine.redo() - - expect(engine.getSheetNames()).toEqual(['Sheet1']) - }) - - it('redo removes scoped named expressions', () => { - const engine = HyperFormula.buildFromSheets({ - Sheet1: [['=MyName']], - }) - engine.addNamedExpression('MyName', '=42', 0) - engine.removeSheet(0) - engine.undo() - engine.redo() - - expect(engine.listNamedExpressions().length).toBe(0) - }) -}) - -describe('Redo - adding sheet', () => { - it('re-adds named sheet after undo', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addSheet('SomeSheet') - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expect(engine.getSheetName(1)).toBe('SomeSheet') - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-adds auto-named sheet after undo', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addSheet() - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expect(engine.getSheetName(1)).toBe('Sheet2') - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('addSheet clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.addSheet() - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) - - it('restores cross-sheet reference after redo', () => { - const engine = HyperFormula.buildFromArray([['=NewSheet!A1']]) - engine.addSheet('NewSheet') - engine.undo() - engine.redo() - - expect(engine.getSheetName(1)).toBe('NewSheet') - }) - - it('builds formulas correctly with suspended evaluation during redo addSheet', () => { - const engine = HyperFormula.buildFromArray([['=NewSheet!A1']]) - engine.addSheet('NewSheet') - const snapshot = engine.getAllSheetsSerialized() - - engine.undo() - engine.suspendEvaluation() - engine.redo() - engine.resumeEvaluation() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) -}) - -describe('Redo - renaming sheet', () => { - it('re-applies sheet rename after undo', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'Foo') - engine.undo() - - engine.redo() - - expect(engine.getSheetName(0)).toBe('Foo') - }) - - it('renameSheet clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.renameSheet(0, 'Foo') - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) - - it('redo rename with case change only', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'SHEET1') - engine.undo() - engine.redo() - - expect(engine.getSheetName(0)).toBe('SHEET1') - }) - - it('redo rename preserves cell values', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[42], ['=A1*2']]}) - engine.renameSheet(0, 'NewName') - engine.undo() - engine.redo() - - expect(engine.getSheetName(0)).toBe('NewName') - expect(engine.getCellValue(adr('A1'))).toBe(42) - expect(engine.getCellValue(adr('A2'))).toBe(84) - }) - - it('redo rename with suspended evaluation', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'Foo') - engine.undo() - engine.suspendEvaluation() - engine.redo() - engine.resumeEvaluation() - - expect(engine.getSheetName(0)).toBe('Foo') - }) - - it('redo rename that merged with placeholder sheet', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=OldName!A1', '=NewName!A1']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(42) - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.redo() - - expect(engine.getSheetName(oldNameId)).toBe('NewName') - expect(engine.getCellFormula(adr('A1', sheet1Id))).toBe('=NewName!A1') - expect(engine.getCellFormula(adr('B1', sheet1Id))).toBe('=NewName!A1') - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(42) - }) - - it('redo rename with range reference updates formula (merged with placeholder sheet)', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=SUM(OldName!A1:B2)', '=SUM(NewName!A1:B2)']], - 'OldName': [[10, 20], [30, 40]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.renameSheet(oldNameId, 'NewName') - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(100) - - engine.undo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('B1', sheet1Id))).toEqualError(detailedError(ErrorType.REF, ErrorMessage.SheetRef)) - - engine.redo() - - expect(engine.getCellFormula(adr('A1', sheet1Id))).toBe('=SUM(NewName!A1:B2)') - expect(engine.getCellFormula(adr('B1', sheet1Id))).toBe('=SUM(NewName!A1:B2)') - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(100) - }) - - it('redo multiple sequential renames', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.renameSheet(0, 'Name1') - engine.renameSheet(0, 'Name2') - engine.renameSheet(0, 'Name3') - engine.undo() - engine.undo() - engine.undo() - engine.redo() - - expect(engine.getSheetName(0)).toBe('Name1') - - engine.redo() - - expect(engine.getSheetName(0)).toBe('Name2') - - engine.redo() - - expect(engine.getSheetName(0)).toBe('Name3') - }) - - it('redo rename combined with cell content changes', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]]}) - engine.setCellContents(adr('A1'), 10) - engine.renameSheet(0, 'NewName') - engine.setCellContents(adr('A1'), 100) - engine.undo() - engine.undo() - engine.undo() - engine.redo() - - expect(engine.getCellValue(adr('A1'))).toBe(10) - - engine.redo() - - expect(engine.getSheetName(0)).toBe('NewName') - - engine.redo() - - expect(engine.getCellValue(adr('A1'))).toBe(100) - }) - - it('redo rename in batch mode', () => { - const engine = HyperFormula.buildFromSheets({'Sheet1': [[1]], 'Sheet2': [[2]]}) - engine.batch(() => { - engine.renameSheet(0, 'NewName1') - engine.renameSheet(1, 'NewName2') - }) - engine.undo() - engine.redo() - - expect(engine.getSheetName(0)).toBe('NewName1') - expect(engine.getSheetName(1)).toBe('NewName2') - }) - - it('redo rename with chained dependencies across sheets', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=Sheet2!A1+2']], - 'Sheet2': [['=NewName!A1*2']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const sheet2Id = engine.getSheetId('Sheet2')! - const oldNameId = engine.getSheetId('OldName')! - - engine.renameSheet(oldNameId, 'NewName') - engine.undo() - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet2Id))).toBe(84) - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(86) - }) - - it('redo rename with named expressions referencing placeholder', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=MyValue']], - 'OldName': [[99]], - }, {}, [ - { name: 'MyValue', expression: '=NewName!$A$1' } - ]) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - engine.renameSheet(oldNameId, 'NewName') - engine.undo() - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(99) - }) - - it('redo rename after undo of combined operations', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=NewName!A1']], - 'OldName': [[42]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - engine.renameSheet(oldNameId, 'NewName') - engine.setCellContents(adr('A1', oldNameId), 100) - engine.undo() - engine.undo() - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(42) - - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(100) - }) - - it('redo rename with multiple cells referencing placeholder', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [['=NewName!A1', '=NewName!B1']], - 'Sheet2': [['=NewName!A1+10', '=NewName!B1+20']], - 'OldName': [[5, 7]], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const sheet2Id = engine.getSheetId('Sheet2')! - const oldNameId = engine.getSheetId('OldName')! - engine.renameSheet(oldNameId, 'NewName') - engine.undo() - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(5) - expect(engine.getCellValue(adr('B1', sheet1Id))).toBe(7) - expect(engine.getCellValue(adr('A1', sheet2Id))).toBe(15) - expect(engine.getCellValue(adr('B1', sheet2Id))).toBe(27) - }) - - it('redo rename with column and row ranges', () => { - const engine = HyperFormula.buildFromSheets({ - 'Sheet1': [ - ['=SUM(NewName!A:A)'], - ['=SUM(NewName!1:2)'], - ], - 'OldName': [ - [1, 2], - [3, 4], - ], - }) - const sheet1Id = engine.getSheetId('Sheet1')! - const oldNameId = engine.getSheetId('OldName')! - engine.renameSheet(oldNameId, 'NewName') - engine.undo() - engine.redo() - - expect(engine.getCellValue(adr('A1', sheet1Id))).toBe(4) - expect(engine.getCellValue(adr('A2', sheet1Id))).toBe(10) - }) -}) - -describe('Redo - clearing sheet', () => { - it('re-clears sheet after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - engine.clearSheet(0) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('clearSheet clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.clearSheet(0) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - adding columns', () => { - it('re-adds column after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '3'], - ]) - engine.addColumns(0, [1, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('dummy addColumns operation is redoable', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - engine.addColumns(0, [1000, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-adds multiple column segments after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3'], - ]) - engine.addColumns(0, [1, 1], [2, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('addColumns clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.addColumns(0, [1000, 1]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - removing column', () => { - it('re-removes empty column after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1', null, '3'], - ]) - engine.removeColumns(0, [1, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-removes column with values and formulas after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ['=B1'] - ]) - engine.removeColumns(0, [0, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('re-removes multiple column segments after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2', '3', '4'], - ]) - engine.removeColumns(0, [1, 1], [3, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('dummy removeColumns operation is redoable', () => { - const engine = HyperFormula.buildFromArray([ - ['1'] - ]) - engine.removeColumns(0, [1000, 1]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('removeColumns clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.removeColumns(0, [1000, 1]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - cut-paste', () => { - it('re-applies cut-paste after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['foo'], - ['bar'], - ]) - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('cut does not clear redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - - expect(engine.isThereSomethingToRedo()).toBe(true) - }) - - it('cut-paste clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.cut(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - copy-paste', () => { - it('re-applies copy-paste after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['foo', 'baz'], - ['bar', 'faz'], - ]) - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 2, 2)) - engine.paste(adr('C3')) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('copy does not clear redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - - expect(engine.isThereSomethingToRedo()).toBe(true) - }) - - it('copy-paste clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.copy(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1)) - engine.paste(adr('A2')) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - setting sheet contents', () => { - it('re-applies sheet content change after undo', () => { - const engine = HyperFormula.buildFromArray([['13']]) - engine.setSheetContent(0, [['42']]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('clears extra cells when redoing setSheetContent', () => { - const engine = HyperFormula.buildFromArray([['13', '14']]) - engine.setSheetContent(0, [['42']]) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) - - it('setSheetContent clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.setSheetContent(0, [['42']]) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - add named expression', () => { - it('re-adds named expression after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo'] - ]) - - engine.addNamedExpression('foo', 'foo') - engine.undo() - - engine.redo() - - expect(engine.listNamedExpressions().length).toBe(1) - expect(engine.getCellValue(adr('A1'))).toBe('foo') - }) - - it('addNamedExpression clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.addNamedExpression('foo', 'foo') - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - remove named expression', () => { - it('re-removes named expression after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo'] - ]) - - engine.addNamedExpression('foo', 'foo') - engine.removeNamedExpression('foo') - engine.undo() - - engine.redo() - - expect(engine.listNamedExpressions().length).toBe(0) - expect(engine.getCellValue(adr('A1'))).toEqualError(detailedError(ErrorType.NAME, ErrorMessage.NamedExpressionName('foo'))) - }) - - it('removeNamedExpression clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('foo', 'foo') - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.removeNamedExpression('foo') - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - change named expression', () => { - it('re-applies expression change after undo', () => { - const engine = HyperFormula.buildFromArray([ - ['=foo'] - ]) - - engine.addNamedExpression('foo', 'foo') - engine.changeNamedExpression('foo', 'bar') - engine.undo() - - engine.redo() - - expect(engine.listNamedExpressions().length).toBe(1) - expect(engine.getCellValue(adr('A1'))).toBe('bar') - }) - - it('changeNamedExpression clears redo stack', () => { - const engine = HyperFormula.buildFromArray([]) - engine.addNamedExpression('foo', 'foo') - engine.setCellContents(adr('A1'), 42) - engine.undo() - - engine.changeNamedExpression('foo', 'foo') - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) -}) - -describe('Redo - batch mode', () => { - it('multiple batched operations are one redo', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '2'], - ]) - engine.batch(() => { - engine.setCellContents(adr('A1'), '10') - engine.setCellContents(adr('A2'), '20') - }) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - - expect(engine.isThereSomethingToRedo()).toBe(false) - }) - - it('operations in batch mode are re-done in correct order', () => { - const engine = HyperFormula.buildFromArray([ - ['1'], - ]) - engine.batch(() => { - engine.setCellContents(adr('A1'), '10') - engine.removeRows(0, [0, 1]) - }) - const snapshot = engine.getAllSheetsSerialized() - engine.undo() - - engine.redo() - - expectEngineToBeTheSameAs(engine, HyperFormula.buildFromSheets(snapshot)) - }) -}) - -describe('Redo', () => { - it('throws error when redo stack is empty', () => { - const engine = HyperFormula.buildEmpty() - - expect(() => { - engine.redo() - }).toThrow(new NoOperationToRedoError()) - }) - - it('redo recomputes and return changes', () => { - const engine = HyperFormula.buildFromArray([ - ['3', '=A1'], - ]) - engine.setCellContents(adr('A1'), '100') - engine.undo() - - const changes = engine.redo() - - expect(engine.getCellValue(adr('B1'))).toBe(100) - expect(changes.length).toBe(2) - }) -}) diff --git a/test/unit/unsupported-types.spec.ts b/test/unit/unsupported-types.spec.ts deleted file mode 100644 index 8062994e64..0000000000 --- a/test/unit/unsupported-types.spec.ts +++ /dev/null @@ -1,118 +0,0 @@ -import {HyperFormula} from '../../src' -import {adr} from './testUtils' - -const BigIntSupported = (function(): boolean { - try { - const bigint = BigInt(1) - return typeof bigint === 'bigint' - } catch (e) { - return false - } -})() - -describe('unsupported types should result in error', () => { - it('should give parsing error #1', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[[]]]) - ).toThrowError('Unable to parse value: []') - }) - it('should give parsing error #2', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[{}]]) - ).toThrowError('Unable to parse value: {}') - }) - it('should give parsing error #3', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[() => {}]])) - .toThrowError(/^Unable to parse value\: "(\(\) => \{\s*\}|function \(\) \{\s*\})"$/) - }) - it('should give parsing error #4', () => { - expect(() => HyperFormula.buildFromSheets({ - // eslint-disable-next-line - // @ts-ignore - Sheet1: [[() => {}]], - // eslint-disable-next-line - // @ts-ignore - Sheet2: [[() => {}]] - })) - .toThrowError(/^Unable to parse value\: "(\(\) \=\> \{\s*\}|function \(\) \{\s*\})"$/) - }) - it('should give parsing error #5', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[Symbol()]]) - ).toThrowError('Unable to parse value: \"Symbol()\"') - }) - it('should give parsing error #6', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[/abcd/]]) - ).toThrowError('Unable to parse value: \"RegExp(/abcd/)\"') - }) - it('should give parsing error #7', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[{sym: Symbol()}]]) - ).toThrowError('Unable to parse value: {\n' + - ' \"sym\": \"Symbol()\"\n' + - '}') - }) - it('should give parsing error #9', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[Symbol('a')]]) - ).toThrowError('Unable to parse value: \"Symbol(a)\"') - }) - it('should give parsing error #10', () => { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[[Symbol(/abcd/)]]]) - ).toThrowError('Unable to parse value: [\n' + - ' \"Symbol(/abcd/)\"\n' + - ']') - }) - it('should give parsing error #11', () => { - if (BigIntSupported) { - // eslint-disable-next-line - // @ts-ignore - expect(() => HyperFormula.buildFromArray([[BigInt(9007199254740991)]]) - ).toThrowError('Unable to parse value: \"BigInt(9007199254740991)\"') - } - }) - it('should give parsing error for setCellContents', () => { - const sheet = [ - [], - ] - const engine = HyperFormula.buildFromArray(sheet) - // eslint-disable-next-line - // @ts-ignore - expect(() => engine.setCellContents(adr('A1'), () => {})) - .toThrowError(/^Unable to parse value\: "(\(\) \=\> \{\s*\}|function \(\) \{\s*\})"$/) - // eslint-disable-next-line - // @ts-ignore - expect(() => engine.setSheetContent(0, [[() => {}]])) - .toThrowError(/^Unable to parse value\: "(\(\) \=\> \{\s*\}|function \(\) \{\s*\})"$/) - }) - - it('should give error when not an array', () => { - const sheet = [ - [], - ] - const engine = HyperFormula.buildFromArray(sheet) - // eslint-disable-next-line - // @ts-ignore - expect(() => engine.setSheetContent(0, 1) - ).toThrowError('Invalid arguments, expected an array of arrays.') - // eslint-disable-next-line - // @ts-ignore - expect(() => engine.setSheetContent(0, [1]) - ).toThrowError('Invalid arguments, expected an array of arrays.') - // eslint-disable-next-line - // @ts-ignore - expect(() => engine.setCellContents(adr('A1'), [1])) - .toThrowError('Invalid arguments, expected an array of arrays or a raw cell value.') - }) -}) diff --git a/test/unit/update-config.spec.ts b/test/unit/update-config.spec.ts deleted file mode 100644 index 15e0925e27..0000000000 --- a/test/unit/update-config.spec.ts +++ /dev/null @@ -1,125 +0,0 @@ -import {HyperFormula, ErrorType} from '../../src' -import {ErrorMessage} from '../../src/error-message' -import {plPL} from '../../src/i18n/languages' -import {adr, detailedError, resetSpy} from './testUtils' -import {BuildEngineFactory} from '../../src/BuildEngineFactory' - -describe('update config', () => { - it('simple reload preserves all values', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1', '=SUM(A1:B1)'], - ['#DIV/0!', '=B2', '=F('] - ]) - engine.updateConfig({}) - - expect(engine.getCellValue(adr('A1'))).toBe(1) - expect(engine.getCellValue(adr('B1'))).toBe(1) - expect(engine.getCellValue(adr('C1'))).toBe(2) - expect(engine.getCellValue(adr('A2'))).toEqualError(detailedError(ErrorType.DIV_BY_ZERO)) - expect(engine.getCellValue(adr('B2'))).toEqualError(detailedError(ErrorType.CYCLE)) - expect(engine.getCellValue(adr('C2'))).toEqualError(detailedError(ErrorType.ERROR, ErrorMessage.ParseError)) - }) - it('simple reload preserves formulas', () => { - const engine = HyperFormula.buildFromArray([ - ['1', '=A1', '=SUM(A1:B1)'], - ['#DIV/0!', '=B2', '=F('] - ]) - engine.updateConfig({}) - - expect(engine.getCellFormula(adr('B1'))).toBe('=A1') - expect(engine.getCellFormula(adr('C1'))).toBe('=SUM(A1:B1)') - expect(engine.getCellFormula(adr('B2'))).toBe('=B2') - expect(engine.getCellFormula(adr('C2'))).toBe('=F(') - }) - - it('simple reload preserves values', () => { - const engine = HyperFormula.buildFromArray([ - ['1.00000000000001', '1', '=A1-B1'], - ], {smartRounding: false}) - expect(engine.getCellValue(adr('C1'))).toBeCloseTo(0.00000000000001) - - engine.updateConfig({smartRounding: true}) - - expect(engine.getCellValue(adr('C1'))).toEqual(0) - }) - it('language reload', () => { - HyperFormula.registerLanguage('plPL', plPL) - const engine = HyperFormula.buildFromArray([ - ['=FOO()', '=SUM()', '=SUMA()', 'SUM()', '=SUM('], - ]) - engine.updateConfig({language: 'plPL'}) - - expect(engine.getCellFormula(adr('A1'))).toBe('=FOO()') - expect(engine.getCellFormula(adr('B1'))).toBe('=SUMA()') - expect(engine.getCellFormula(adr('C1'))).toBe('=SUMA()') - expect(engine.getCellFormula(adr('D1'))).toBe(undefined) - expect(engine.getCellFormula(adr('E1'))).toBe('=SUM(') - }) - - it('simple reload preserves namedexpressions', () => { - const engine = HyperFormula.buildFromArray([ - ['=TRUE', '=FALSE'], - ]) - engine.addNamedExpression('TRUE', true) - engine.addNamedExpression('FALSE', false) - engine.updateConfig({}) - - expect(engine.getCellValue(adr('A1'))).toBe(true) - expect(engine.getCellValue(adr('B1'))).toBe(false) - }) - - it('doesn\'t rebuild the engine when new config is the same as the old one', () => { - const config = { useArrayArithmetic: true } - const engine = HyperFormula.buildFromArray([[]], config) - - const rebuildEngineSpy = spyOn(BuildEngineFactory, 'rebuildWithConfig') - resetSpy(rebuildEngineSpy) - - engine.updateConfig(config) - expect(rebuildEngineSpy).not.toHaveBeenCalled() - }) - - it('rebuilds the engine when new config adds new timeFormat to the same instance of timeFormats array', () => { - const config = { timeFormats: ['hh:mm:ss.sss'] } - const engine = HyperFormula.buildFromArray([[]], config) - - const rebuildEngineSpy = spyOn(BuildEngineFactory, 'rebuildWithConfig') - resetSpy(rebuildEngineSpy) - - config.timeFormats.push('hh:mm:ss') - engine.updateConfig(config) - expect(rebuildEngineSpy).toHaveBeenCalled() - }) - - it('rebuilds the engine when new config adds new currencySymbol to the same instance of currencySymbol array', () => { - const config = { currencySymbol: ['$'] } - const engine = HyperFormula.buildFromArray([[]], config) - - const rebuildEngineSpy = spyOn(BuildEngineFactory, 'rebuildWithConfig') - resetSpy(rebuildEngineSpy) - - config.currencySymbol.push('€') - engine.updateConfig(config) - expect(rebuildEngineSpy).toHaveBeenCalled() - }) - - it('doesn\'t rebuild the engine when new config contains only the default config values', () => { - const engine = HyperFormula.buildFromArray([[]], {}) - - const rebuildEngineSpy = spyOn(BuildEngineFactory, 'rebuildWithConfig') - resetSpy(rebuildEngineSpy) - - engine.updateConfig({ useColumnIndex: false, functionArgSeparator: ',', undoLimit: 20 }) - expect(rebuildEngineSpy).not.toHaveBeenCalled() - }) - - it('doesn\'t throw after adding named expression (#1194)', () => { - const hf = HyperFormula.buildFromArray([['=42']], { - licenseKey: 'gpl-v3' - }) - - - hf.addNamedExpression('ABC', '=Sheet1!$A$1') - expect(() => hf.updateConfig({ maxRows: 101 })).not.toThrow() - }) -}) diff --git a/test/unit/volatile-functions.spec.ts b/test/unit/volatile-functions.spec.ts deleted file mode 100644 index f0980bcdb6..0000000000 --- a/test/unit/volatile-functions.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import {HyperFormula} from '../../src' -import {AbsoluteCellRange} from '../../src/AbsoluteCellRange' -import {adr} from './testUtils' - -describe('Interpreter - function RAND', () => { - it('works', () => { - const engine = HyperFormula.buildFromArray([ - ['=RAND()', '42'], - ]) - const valueBeforeRecomputation = engine.getCellValue(adr('A1')) - - engine.setCellContents(adr('B1'), '35') - - expect(engine.getCellValue(adr('A1'))).not.toEqual(valueBeforeRecomputation) - }) - - it('cell which is dependent on volatile formula is also recomputed', () => { - const engine = HyperFormula.buildFromArray([ - ['=RAND()', '42', '=A1'], - ]) - const valueBeforeRecomputation = engine.getCellValue(adr('C1')) - - engine.setCellContents(adr('B1'), '35') - - expect(engine.getCellValue(adr('C1'))).not.toEqual(valueBeforeRecomputation) - }) - - it('formula can be recognized as volatile even if entered later', () => { - const engine = HyperFormula.buildFromArray([ - ['=A2+A3', '42'], - ]) - - engine.setCellContents(adr('A1'), '=RAND()') - - const a1 = engine.addressMapping.getCell(adr('A1'))! - expect(engine.dependencyGraph.verticesToRecompute()).toEqual([a1]) - }) - - it('volatile vertices should not be recomputed after removing from graph', () => { - const engine = HyperFormula.buildFromArray([ - ['=RAND()', '42'], - ]) - - engine.setCellContents(adr('A1'), '35') - - expect(engine.dependencyGraph.verticesToRecompute()).toEqual([]) - }) - - it('volatile formula after moving is still volatile', () => { - const engine = HyperFormula.buildFromArray([ - ['=RAND()', '42'], - ]) - - engine.moveCells(AbsoluteCellRange.spanFrom(adr('A1'), 1, 1), adr('A2')) - - const a2 = engine.addressMapping.getCell(adr('A2'))! - expect(engine.dependencyGraph.verticesToRecompute()).toEqual([a2]) - }) -}) diff --git a/tsconfig.test.json b/tsconfig.test.json deleted file mode 100644 index 0fced1bfdb..0000000000 --- a/tsconfig.test.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "outDir": "./test-jasmine", - /* Make sure proper types are used */ - "types": ["jasmine", "node", "webpack-env"], - "sourceMap": true - }, - "extends": "./tsconfig", - "include": ["src", "test"], - /* Exclude files that are specific for jest setup */ - "exclude": ["test/unit/_setupFiles/jest"] -}