Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 5 additions & 114 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,117 +1,8 @@
name: CI
name: ✅ test

on:
push:
branches: [master]
pull_request:
branches: [master]
on: [push, pull_request]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 验证上一版 `.github/workflows/main.yml` 是否在 `on:` 下保留了分支过滤条件。
# 预期:如果旧文件里在 `push` / `pull_request` 下存在 `branches:`,
# 说明这次改动放宽了触发范围,需要把过滤条件补回。

prev="$(git log --format=%H -- .github/workflows/main.yml | sed -n '2p')"
if [ -z "$prev" ]; then
  echo "本地历史里没有找到 .github/workflows/main.yml 的上一版。" >&2
  exit 1
fi

echo "=== 上一版 workflow 头部 ($prev) ==="
git show "${prev}:.github/workflows/main.yml" | sed -n '1,40p'

echo
echo "=== 当前 workflow 头部 ==="
sed -n '1,40p' .github/workflows/main.yml

Repository: react-component/mini-decimal

Length of output: 1817


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 检查当前工作区是否存在 .github/workflows/main.yml
if [ -f ".github/workflows/main.yml" ]; then
  echo "=== 当前 workflow on: 配置 (前 20 行) ==="
  head -20 .github/workflows/main.yml
  echo
fi

# 尝试查看 git 历史(如果存在)
if git rev-parse --git-dir > /dev/null 2>&1; then
  echo "=== Git 历史查询 ==="
  # 获取涉及该文件的最近 3 个提交
  git log --oneline -n 3 -- .github/workflows/main.yml 2>/dev/null || echo "无法访问 git 历史"
  echo
  
  # 尝试获取前一个版本
  prev_commit=$(git log --format=%H -- .github/workflows/main.yml 2>/dev/null | sed -n '2p')
  if [ -n "$prev_commit" ]; then
    echo "=== 前一版本 workflow on: 配置 ($prev_commit) ==="
    git show "${prev_commit}:.github/workflows/main.yml" 2>/dev/null | head -20 || echo "无法显示前一版本"
  fi
else
  echo "当前目录不是 git 仓库"
fi

Repository: react-component/mini-decimal

Length of output: 308


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== 查看 .github/workflows/main.yml 的完整 git 历史 ==="
git log --all --oneline -- .github/workflows/main.yml | head -10

echo
echo "=== 显示当前版本的完整内容 ==="
cat .github/workflows/main.yml

echo
echo "=== 尝试显示前一个版本 ==="
# 获取所有涉及该文件的提交
commits=$(git log --format=%H --all -- .github/workflows/main.yml)
commit_array=($commits)

if [ ${`#commit_array`[@]} -gt 1 ]; then
  echo "前一版本提交: ${commit_array[1]}"
  git show "${commit_array[1]}:.github/workflows/main.yml" 2>/dev/null || echo "无法显示"
else
  echo "只有一个提交,无法比较"
  # 尝试显示该提交中的变更
  if [ ${`#commit_array`[@]} -gt 0 ]; then
    echo "显示当前提交 ${commit_array[0]} 中对该文件的改动:"
    git show "${commit_array[0]}":".github/workflows/main.yml" 2>/dev/null || echo "无法显示"
  fi
fi

Repository: react-component/mini-decimal

Length of output: 3224


🏁 Script executed:

#!/bin/bash
# 显示应该的修复方案
echo "=== 应该恢复的配置 ==="
cat <<'EOF'
on:
  push:
    branches: [master]
  pull_request:
    branches: [master]
EOF

Repository: react-component/mini-decimal

Length of output: 161


需要恢复 workflow 的分支过滤条件。

Line 3 将触发器改成了无条件的 on: [push, pull_request],而原配置在 pushpull_request 上都限制了 branches: [master]。这扩大了 CI 触发范围,与 PR 目标中的"保持现有行为"不符。请将分支过滤条件恢复:

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/main.yml at line 3, 恢复 workflow 的分支过滤:不要使用无条件的 "on: [push,
pull_request]",而是将触发器改回分别声明 push 和 pull_request 并限制 branches 为 master(使用 keys:
on -> push -> branches: [master] 和 on -> pull_request -> branches:
[master]),以恢复原有 CI 触发范围。


jobs:
setup:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master

- uses: actions/setup-node@v1
with:
node-version: '12'

- name: cache package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}

- name: create package-lock.json
run: npm i --package-lock-only

- name: hack for singe file
run: |
if [ ! -d "package-temp-dir" ]; then
mkdir package-temp-dir
fi
cp package-lock.json package-temp-dir

- name: cache node_modules
id: node_modules_cache_id
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}

- name: install
if: steps.node_modules_cache_id.outputs.cache-hit != 'true'
run: npm ci

lint:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master

- name: restore cache from package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}

- name: restore cache from node_modules
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}

- name: lint
run: npm run lint

- name: ts check
run: npm run lint:tsc

needs: setup

compile:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master

- name: restore cache from package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}

- name: restore cache from node_modules
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}

- name: compile
run: npm run compile

needs: setup

coverage:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@master

- name: restore cache from package-lock.json
uses: actions/cache@v2
with:
path: package-temp-dir
key: lock-${{ github.sha }}

- name: restore cache from node_modules
uses: actions/cache@v2
with:
path: node_modules
key: node_modules-${{ hashFiles('**/package-temp-dir/package-lock.json') }}

- name: coverage
run: npm test -- --coverage && bash <(curl -s https://codecov.io/bash)

needs: setup
test:
uses: react-component/rc-test/.github/workflows/test.yml@main
secrets: inherit
Comment on lines +7 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

git ls-files | grep -E "\.github/workflows"

Repository: react-component/mini-decimal

Length of output: 128


🏁 Script executed:

cat -n .github/workflows/main.yml

Repository: react-component/mini-decimal

Length of output: 268


不要把继承 secrets 的复用工作流绑定到 @main

Line 7 引用的是外部仓库的 reusable workflow,Line 8 又继承了全部 secrets。@main 是可变引用,上游后续提交会直接改变这里执行的 CI 内容;和 secrets: inherit 组合后,供应链与最小权限风险都会被放大。建议固定到 commit SHA,并改成按 workflow_call 显式传递所需 secrets。

建议修改
-    uses: react-component/rc-test/.github/workflows/test.yml@main
+    uses: react-component/rc-test/.github/workflows/test.yml@<pinned-commit-sha>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/main.yml around lines 7 - 8, 不要将可复用工作流引用固定为 `@main` 并同时使用
secrets: inherit;把 uses: react-component/rc-test/.github/workflows/test.yml@main
改为指向上游仓库的不可变 commit SHA (例如 ...@<commit-sha>),并删除 secrets: inherit,然后通过上游工作流的
workflow_call 输入或显式 environment/with 参数传递仅需的单个 secrets(或在调用处从 repository secrets
显式注入),确保在调用处列出具体 secret 名称而不是继承全部,以减少供应链与权限风险。

4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ yarn.lock
/es/
package-lock.json
.doc
.dumi
dist

# umi
.umi
.umi-production
.umi-test
.env.local
.env.local
8 changes: 3 additions & 5 deletions .umirc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
import { defineConfig } from 'dumi';

export default defineConfig({
title: 'rc-mini-decimal',
favicon: 'https://avatars0.githubusercontent.com/u/9441414?s=200&v=4',
logo: 'https://avatars0.githubusercontent.com/u/9441414?s=200&v=4',
outputPath: '.doc',
exportStatic: {},
themeConfig: {
name: 'mini-decimal',
},
styles: [
`
.markdown table {
Expand Down
39 changes: 20 additions & 19 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,39 @@
"compile": "father build",
"deploy": "npm run docs:build && npm run docs:deploy",
"docs:build": "dumi build",
"docs:deploy": "gh-pages -d docs-dist",
"docs:deploy": "gh-pages -d dist",
"coverage": "rc-test --coverage",
"lint": "eslint src/ --ext .tsx,.ts",
"lint:tsc": "tsc -p tsconfig.json --noEmit",
"now-build": "npm run docs:build",
"prepublishOnly": "npm run compile && np --no-cleanup --yolo --no-publish",
"prepublishOnly": "npm run compile && rc-np",
"prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"",
"start": "dumi dev",
"test": "umi-test",
"test:coverage": "npm run test --coverage",
"test": "rc-test",
"watch": "father dev"
},
"dependencies": {
"@babel/runtime": "^7.18.0"
},
"devDependencies": {
"@rc-component/father-plugin": "^1.0.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.0.0",
"@types/jest": "^26.0.20",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@umijs/fabric": "^2.5.2",
"dumi": "^1.1.0",
"eslint": "^7.18.0",
"father": "^4.0.0-rc.8",
"gh-pages": "^3.1.0",
"np": "^5.0.3",
"prettier": "^2.1.2",
"@rc-component/father-plugin": "^2.0.4",
"@rc-component/np": "^1.0.4",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^16.1.0",
"@types/jest": "^29.5.12",
"@types/node": "^22.1.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@umijs/fabric": "^4.0.1",
"dumi": "^2.3.8",
"eslint": "^8.57.0",
"father": "^4.4.4",
"gh-pages": "^6.1.1",
"prettier": "^3.3.3",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"typescript": "^4.6.3",
"umi-test": "^1.9.7"
"rc-test": "^7.0.15",
"typescript": "^5.4.5"
},
"engines": {
"node": ">=8.x"
Expand Down
6 changes: 5 additions & 1 deletion src/NumberDecimal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { DecimalClass, ValueType } from './interface';
import { getNumberPrecision, isEmpty, num2str } from './numberUtil';
import { getNumberPrecision, isE, isEmpty, num2str } from './numberUtil';

/**
* We can remove this when IE not support anymore
Expand Down Expand Up @@ -110,6 +110,10 @@ export default class NumberDecimal implements DecimalClass {
return '';
}

if (isE(this.number) && getNumberPrecision(this.number) > 100) {
return String(this.number);
}

return num2str(this.number);
}
}
85 changes: 77 additions & 8 deletions src/numberUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,77 @@ export function isE(number: string | number) {
return !Number.isNaN(Number(str)) && str.includes('e');
}

type ParsedScientificNotation = {
decimal: string;
digits: string;
exponent: number;
integer: string;
negative: boolean;
};

/**
* Parse a scientific-notation string into reusable parts.
*
* The idea is to split the value into mantissa and exponent first, then
* normalize the mantissa into sign, integer/decimal segments, and a compact
* digit sequence so later logic can move the decimal point without re-parsing.
*/
function parseScientificNotation(numStr: string): ParsedScientificNotation {
const [mantissa, exponent = '0'] = numStr.toLowerCase().split('e');
const negative = mantissa.startsWith('-');
const unsignedMantissa = negative ? mantissa.slice(1) : mantissa;
const [integer = '0', decimal = ''] = unsignedMantissa.split('.');
const digits = `${integer}${decimal}`.replace(/^0+/, '') || '0';

return {
decimal,
digits,
exponent: Number(exponent),
integer,
negative,
};
}

/**
* Expand parsed scientific notation into a plain decimal string.
*
* The core idea is to calculate where the decimal point lands after applying
* the exponent, then rebuild the string by either padding zeros or inserting
* the decimal point inside the normalized digit sequence.
*/
function expandScientificNotation(parsed: ParsedScientificNotation) {
const { decimal, digits, exponent, integer, negative } = parsed;

if (digits === '0') {
return '0';
}

const integerDigits = integer.replace(/^0+/, '').length;
const leadingDecimalZeros = (decimal.match(/^0*/) || [''])[0].length;
const initialDecimalIndex = integerDigits || -leadingDecimalZeros;
const decimalIndex = initialDecimalIndex + exponent;

let expanded = '';

if (decimalIndex <= 0) {
expanded = `0.${'0'.repeat(-decimalIndex)}${digits}`;
} else if (decimalIndex >= digits.length) {
expanded = `${digits}${'0'.repeat(decimalIndex - digits.length)}`;
} else {
expanded = `${digits.slice(0, decimalIndex)}.${digits.slice(decimalIndex)}`;
}

return `${negative ? '-' : ''}${expanded}`;
}

function getScientificPrecision(parsed: ParsedScientificNotation) {
if (parsed.exponent >= 0) {
return Math.max(0, parsed.decimal.length - parsed.exponent);
}

return Math.abs(parsed.exponent) + parsed.decimal.length;
}

/**
* [Legacy] Convert 1e-9 to 0.000000001.
* This may lose some precision if user really want 1e-9.
Expand All @@ -67,13 +138,7 @@ export function getNumberPrecision(number: string | number) {
const numStr: string = String(number);

if (isE(number)) {
let precision = Number(numStr.slice(numStr.indexOf('e-') + 2));

const decimalMatch = numStr.match(/\.(\d+)/);
if (decimalMatch?.[1]) {
precision += decimalMatch[1].length;
}
return precision;
return getScientificPrecision(parseScientificNotation(numStr));
}

return numStr.includes('.') && validateNumber(numStr)
Expand All @@ -99,7 +164,11 @@ export function num2str(number: number): string {
);
}

numStr = number.toFixed(getNumberPrecision(numStr));
const parsed = parseScientificNotation(numStr);
const precision = getScientificPrecision(parsed);

numStr =
precision > 100 ? expandScientificNotation(parsed) : number.toFixed(precision);
}

return trimNumber(numStr).fullStr;
Expand Down
20 changes: 20 additions & 0 deletions tests/util.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import getMiniDecimal, {
toFixed,
} from '../src/MiniDecimal';
import type { DecimalClass, ValueType } from '../src/MiniDecimal';
import { num2str } from '../src/numberUtil';

jest.mock('../src/supportUtil');
const { supportBigInt } = require('../src/supportUtil');
Expand Down Expand Up @@ -38,6 +39,8 @@ describe('InputNumber.Util', () => {

classList.forEach(({ name, getDecimal, mockSupportBigInt }) => {
describe(name, () => {
const tinyScientificValue = `0.${'0'.repeat(306)}1`;

beforeEach(() => {
supportBigInt.mockImplementation(() => {
return mockSupportBigInt !== false;
Expand All @@ -61,6 +64,12 @@ describe('InputNumber.Util', () => {
expect(getDecimal('1.').toString()).toEqual('1');
});

it('parses very small scientific notation', () => {
expect(getDecimal('1e-307').toString()).toEqual(
mockSupportBigInt === false ? '1e-307' : tinyScientificValue,
);
});

it('invalidate', () => {
expect(getDecimal('abc').toString()).toEqual('');
});
Expand Down Expand Up @@ -135,6 +144,17 @@ describe('InputNumber.Util', () => {
});
});

describe('scientific notation', () => {
it('keeps num2str behavior correct', () => {
expect(num2str(0.123e-1)).toEqual('0.0123');
expect(num2str(-0.123e-1)).toEqual('-0.0123');
expect(num2str(0.00123e2)).toEqual('0.123');
expect(num2str(0e5)).toEqual('0');
expect(num2str(1.23e-19)).toEqual(`0.${'0'.repeat(18)}123`);
expect(num2str(-1.23e-20)).toEqual(`-0.${'0'.repeat(19)}123`);
});
});

describe('toFixed', () => {
it('less than precision', () => {
expect(toFixed('1.1', ',', 2)).toEqual('1,10');
Expand Down
Loading
Loading