Skip to content

fix(dataset): isolate regexp state between filter rows - #21829

Open
WhyTan00 wants to merge 1 commit into
apache:masterfrom
WhyTan00:fix/filter-regexp-row-state-20261108
Open

WhyTan00 wants to merge 1 commit into
apache:masterfrom
WhyTan00:fix/filter-regexp-row-state-20261108

Conversation

@WhyTan00

@WhyTan00 WhyTan00 commented Nov 8, 2026

Copy link
Copy Markdown

Brief Information

This pull request is in the type of:

  • bug fixing
  • new feature
  • others

What does this PR do?

Keep all matching dataset rows when a reg filter uses a global or sticky regular expression, with stable results on repeated updates.

Fixed issues

No linked issue. Reproduction and regression coverage are included below.

Details

Before: What was the problem?

A normal filter using /alpha/gi drops repeated matching rows:

const option = {
    animation: false,
    dataset: [
        {
            dimensions: ['id', 'value', 'amount'],
            source: [
                ['first', 'ALPHA', 1],
                ['second', 'ALPHA', 2],
                ['third', 'ALPHA', 3]
            ]
        },
        { transform: { type: 'filter', config: { dimension: 'value', reg: /alpha/gi } } }
    ],
    xAxis: { type: 'category' },
    yAxis: {},
    series: { type: 'bar', datasetIndex: 1, encode: { x: 'id', y: 'amount' } }
};
chart.setOption(option);

All three values match the configured condition, but the series receives only two rows. The regression reproduces this through setOption, using the repository's normal Jest/jsdom test setup.

The source-module CLI reproduction also runs the normal createSource -> applyDataTransform -> built-in filter path. Starting with a fresh regexp whose lastIndex is zero, the first computation retains first and third; recomputing the same configuration retains only second. g and y patterns show the same issue. A mixed positive/negative dataset also loses a matching row, while a stateless regexp or string condition produces stable correct results.

The transform configuration clone retains RegExp references. RegExpEvaluator then shares the caller's regexp and its lastIndex across rows, so later records depend on previous matches. This conflicts with the documented filter behavior of selecting matching items; reg supports RegExp or string conditions.

After: How does it behave after the fixing?

Create an evaluator-owned regexp and reset its cursor before testing each value. The pattern and flags are preserved, including ignore-case, multiline, and sticky positioning. Duplicate matching records are all retained in order, repeated computations are stable, and the caller's original regexp cursor remains unchanged.

The regexp is cloned once when the condition is parsed, rather than once per row. No new comparator API, dependency, or configuration is introduced. This is independent of #21828: its missing-value type guard is not included here, and the reproduction uses ordinary strings.

Document Info

  • This PR doesn't relate to document changes
  • The document should be updated later
  • The document changes have been made in apache/echarts-doc#xxx

Misc

Security Checking

  • This PR uses security-sensitive Web APIs.

ZRender Changes

  • This PR depends on ZRender changes (ecomfe/zrender#xxx).

Related test cases or examples to use the new APIs

Added 21 regression/control tests through actual data transforms, including one through setOption and resulting series data. On the unchanged base, 17 fail and 4 pass; after the fix, all 21 pass.

Coverage includes array/object rows, repeated computations with g/gi/y/iy, a caller-owned nonzero cursor, ignore-case/multiline flags, sticky anchoring, matching and nonmatching rows, row order, logical/piped filters, ordinary regexp and string controls, and successive setOption calls. No comparator/classifier is mocked.

./node_modules/.bin/jest --config test/ut/jest.config.cjs --runInBand --coverage=false --runTestsByPath test/ut/spec/data/filterTransformRegExp.test.ts
./node_modules/.bin/eslint src/util/conditionalExpression.ts
git diff --check

The CLI source-module output confirms stable row IDs before/after recomputation. Node 24.22.1, TypeScript 4.4.3, Jest 26.6.3, and zrender 6.1.0 were used. The existing local full-project typecheck limitation from incompatible installed ambient dependency declarations remains; no full-project typecheck success is claimed. No dependency/configuration changes are included. Real-browser rendering is unverified; Jest/jsdom/canvas mocks are used for the API data assertions.

Merging options

  • Please squash the commits into a single one when merging.

Other information

OpenAI Codex assisted with the unchanged-source reproduction, narrow implementation, tests, and verification described above.

@echarts-bot

echarts-bot Bot commented Nov 8, 2026

Copy link
Copy Markdown

Thanks for your contribution!
The community will review it ASAP. In the meanwhile, please checkout the coding standard and Wiki about How to make a pull request.

Please DO NOT commit the files in dist, i18n, and ssr/client/dist folders in a non-release pull request. These folders are for release use only.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant