Skip to content

Commit

Permalink
fix: some bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
righ committed Nov 30, 2024
1 parent e3dfef4 commit b883754
Show file tree
Hide file tree
Showing 25 changed files with 458 additions and 107 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: typecheck
on:
push:

workflow_dispatch:

jobs:
type-check:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: e2e
on:
push:
workflow_dispatch:

env:
TZ: 'Asia/Tokyo'

jobs:
run-e2e-tests:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/unittest.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: unittest
on:
push:
workflow_dispatch:

env:
TZ: 'Asia/Tokyo'

jobs:
run-unit-tests:
Expand Down
13 changes: 13 additions & 0 deletions .storybook/examples/basic/size.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import { ComponentStory } from "@storybook/react";
import { CellsByAddressType, constructInitialCells, GridSheet } from "../../../src";
import { TimeDelta } from "../../../src/lib/time";

export default {
title: "Basic",
Expand Down Expand Up @@ -42,6 +43,18 @@ const Sheet = ({ numRows, numCols, defaultWidth, initialCells }: Props) => {
C3: {
value: 3,
},
A4: {
value: new Date("2022-03-05T12:34:56+09:00")
},
B4: {
value: TimeDelta.create(11, 11, 11),
},
C4: {
value: "=A4+B4",
},
A5: {
value: "=A4-13/24",
},
...initialCells,
},
ensured: { numRows, numCols },
Expand Down
30 changes: 30 additions & 0 deletions e2e/time.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { test, expect } from '@playwright/test';

test('time + delta, time + number(days)', async ({ page }) => {
await page.goto('http://localhost:5233/iframe.html?id=basic--small&viewMode=story');
const a4 = page.locator("[data-address='A4']");
const b4 = page.locator("[data-address='B4']");
const c4 = page.locator("[data-address='C4']");
const a5 = page.locator("[data-address='A5']");

expect(await a4.locator('.gs-cell-rendered').textContent()).toBe('2022-03-05 12:34:56');
expect(await b4.locator('.gs-cell-rendered').textContent()).toBe('11:11:11');
expect(await c4.locator('.gs-cell-rendered').textContent()).toBe('2022-03-05 23:46:07');
expect(await a5.locator('.gs-cell-rendered').textContent()).toBe('2022-03-04 23:34:56');
});

test('input DD MMM [YYYY] format', async ({ page }) => {
await page.goto('http://localhost:5233/iframe.html?id=basic--small&viewMode=story');

const b5 = page.locator("[data-address='B5']");
await b5.click();
await page.keyboard.type('30 Nov');
await page.keyboard.press('Enter');
expect(await b5.locator('.gs-cell-rendered').textContent()).toBe('2001-11-29 15:00:00');

const c5 = page.locator("[data-address='C5']");
await c5.click();
await page.keyboard.type('30 Nov 2024');
await page.keyboard.press('Enter');
expect(await c5.locator('.gs-cell-rendered').textContent()).toBe('2024-11-29 15:00:00');
});
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@
"react-dom": ">=16.9.0"
},
"dependencies": {
"date-fns": "^2.28.0",
"date-fns-timezone": "^0.1.4"
"dayjs": "^1.11.13"
},
"resolutions": {
"trim": "^0.0.3",
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ export class Special {
this.name = name;
}
}

export const SECONDS_IN_DAY = 86400;
export const FULLDATE_FORMAT_UTC = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
78 changes: 59 additions & 19 deletions src/formula/functions/__utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,46 @@
import { solveTable } from '../solver';
import { Table } from '../../lib/table';
import { FormulaError } from '../evaluator';
import dayjs from 'dayjs';
import { FULLDATE_FORMAT_UTC } from '../../constants';

export const gt = (left: any, right: any): boolean => {
if (typeof left === 'string' || typeof right === 'string') {
return ensureString(left) > ensureString(right);
}
try {
return ensureNumber(left) > ensureNumber(right);
} catch {
return false;
}
};

export const gte = (left: any, right: any): boolean => {
if (typeof left === 'string' || typeof right === 'string') {
return ensureString(left) >= ensureString(right);
}
try {
return ensureNumber(left) >= ensureNumber(right);
} catch {
return false;
}
};

export const lt = (left: any, right: any): boolean => {
return !gte(left, right);
};

export const lte = (left: any, right: any): boolean => {
return !gt(left, right);
};

export const eq = (left: any, right: any): boolean => {
return ensureString(left) === ensureString(right);
};

export const ne = (left: any, right: any): boolean => {
return !eq(left, right);
}

export const ensureNumber = (value: any, alternative?: number): number => {
if (typeof value === 'undefined' && typeof alternative !== 'undefined') {
Expand All @@ -14,6 +54,9 @@ export const ensureNumber = (value: any, alternative?: number): number => {
const v = stripTable(value, 0, 0);
return ensureNumber(v, alternative);
}
if (value instanceof Date) {
return value.getTime();
}
const num = parseFloat(value as string);
if (isNaN(num)) {
throw new FormulaError('#VALUE!', `${value} cannot be converted to a number`);
Expand All @@ -35,10 +78,7 @@ export const ensureString = (value: any): string => {
switch (value.constructor.name) {
case 'Date': {
const d: Date = value;
if (d.getHours() + d.getMinutes() + d.getSeconds() === 0) {
return d.toLocaleDateString();
}
return d.toLocaleString();
return dayjs(d).format(FULLDATE_FORMAT_UTC);
}
default:
return String(value);
Expand Down Expand Up @@ -77,44 +117,44 @@ export const stripTable = (value: any, y = 0, x = 0) => {
return value;
};

const CONDITION_REGEX = /^(?<expr>|<=|>=|<>|>|<|=)?(?<target>.*)$/;
const CONDITION_REGEX = /^(<=|>=|<>|>|<|=)?(.*)$/;

export const check = (value: any, condition: string) => {
export const check = (value: any, condition: string): boolean => {
const m = condition.match(CONDITION_REGEX);
// eslint-disable-next-line no-unsafe-optional-chaining
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
const { expr = '', target = '' } = m?.groups || {};

const comparison = parseFloat(target);
const [, expr = '', target = ''] = m || [];
let comparison: any = target;
if (expr === '>' || expr === '<' || expr === '>=' || expr === '<=') {
if (isNaN(comparison) === (typeof value === 'number')) {
return false;
if (typeof value === 'number') {
comparison = parseFloat(target);
}
switch (expr) {
case '>':
return value > target;
return gt(value, comparison);
case '>=':
return value >= target;
return gte(value, comparison);
case '<':
return value < target;
return lt(value, comparison);
case '<=':
return value <= target;
return lte(value, comparison);
}
}

const equals = expr === '' || expr === '=';
if (target === '') {
return !value === equals;
// empty target means "" or "<>"
return (value == null || value === '') === equals;
}

if (isNaN(comparison) && (typeof value === 'string' || value instanceof String)) {
if (typeof value === 'string' || value instanceof String) {
const replaced = target
.replace(/~\*/g, '(\\*)')
.replace(/~\?/g, '(\\?)')
.replace(/\*/g, '(.*)')
.replace(/\?/g, '(.?)');
.replace(/\?/g, '(.)');
const regex = RegExp(`^${replaced}$`, 'i');
return regex.test(value as string) === equals;
}
return (value == comparison) === equals;
return eq(value, comparison) === equals;
};
12 changes: 9 additions & 3 deletions src/formula/functions/add.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import dayjs from 'dayjs';

import { FormulaError } from '../evaluator';
import { BaseFunction } from './__base';
import { ensureNumber, stripTable } from './__utils';
import { Table } from '../../lib/table';
import { TimeDelta } from '../../lib/time';
import { addSeconds } from 'date-fns';
import { SECONDS_IN_DAY } from '../../constants';

export class AddFunction extends BaseFunction {
example = 'ADD(2, 3)';
Expand Down Expand Up @@ -36,10 +38,14 @@ export class AddFunction extends BaseFunction {
return v1.add(v2);
}
if (v1 instanceof Date && typeof v2 === 'number') {
return addSeconds(v1, v2);
return dayjs(v1)
.add(v2 * SECONDS_IN_DAY, 'second')
.toDate();
}
if (typeof v1 === 'number' && v2 instanceof Date) {
return addSeconds(v2, v1);
return dayjs(v2)
.add(v1 * SECONDS_IN_DAY, 'second')
.toDate();
}
if (!v1) {
return v2;
Expand Down
Loading

0 comments on commit b883754

Please sign in to comment.