npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@qiun/eslint-plugin-ucharts

v2.0.0

Published

ESLint plugin enforcing Safe TS Subset v4.0 rules for uCharts cross-platform compatibility (Swift/Kotlin/ArkTS/UTS)

Readme

eslint-plugin-ucharts

npm version license

ESLint plugin enforcing Safe TS Subset v4.0 rules for uCharts cross-platform compatibility (Swift / Kotlin / ArkTS / UTS)

Background

uCharts v4 的 core/ 目录代码会被自动转译为 Swift(iOS)Kotlin(Android)ArkTS(HarmonyOS)UTS(uni-app x) 原生代码。为了确保转译成功,core/ 中的 TypeScript 代码必须遵守 Safe TS Subset v4.0 规范。

本插件提供 18 条 ESLint 规则(v2.0),在编码阶段自动检测违反 Safe TS Subset v4.0 的语法,避免转译时出错。

📖 完整规范文档:Safe TS Subset v4.0

Installation

npm install -D @qiun/eslint-plugin-ucharts

Usage

Quick Start: Recommended Config

// eslint.config.mjs (Flat Config)
import uchartsPlugin from '@qiun/eslint-plugin-ucharts';

export default [
  {
    plugins: {
      '@qiun/ucharts': uchartsPlugin
    },
    rules: {
      '@qiun/ucharts/recommended': 'error'
    }
  }
];

Strict Mode (All Rules as Error)

{
  extends: ['plugin:@qiun/ucharts/strict']
}

v4-Production (Production-Ready)

最严格的配置,适用于生产环境发布前最终检查:

{
  extends: ['plugin:@qiun/ucharts/v4-production']
}

Manual Configuration

{
  plugins: ['@qiun/ucharts'],
  rules: {
    '@qiun/ucharts/no-destructuring': 'error',
    '@qiun/ucharts/no-object-spread': 'error',
    '@qiun/ucharts/no-typeof-runtime-check': 'error',    // 🆕 v2.0
    '@qiun/ucharts/no-object-as-map': 'error',            // 🆕 v2.0
    // ... see Rules below
  }
}

Rules (v2.0)

F-Level: Forbidden (Compile-Blocking) — 14 rules

| Rule | ID | Default | Description | |------|----|---------|-------------| | no-destructuring | F-03~F-05 | error | 禁止解构赋值/解构参数 | | no-object-spread | F-06 | error | 禁止对象展开 {...obj} | | no-dynamic-property-access | F-08~F-09 | error | 禁止动态属性访问 obj[key] | | no-index-signature | F-07 | error | 禁止 Index Signature [key: string]: T | | no-for-in | F-17 | error | 禁止 for...in 循环 | | no-with-statement | F-18 | error | 禁止 with 语句 | | no-nested-function | F-21 | error | 禁止嵌套函数声明 | | require-null-over-undefined | M-01 | error | 要求用 null 替代 undefined | | no-web-api-direct | M-07~M-12 | error | 禁止直接调用 Web API | | no-weakmap-proxy | M-04~M-05 | warn | 禁止 WeakMap / Proxy | | no-typeof-runtime-check | F-29 | error | 禁止 typeof 运行时类型检查 🆕 | | no-object-as-map | F-30 | error | 禁止对象作为 Map 使用 🆕 | | require-explicit-return-type | F-31 | warn | 要求显式返回类型注解 🆕 | | no-double-type-cast | F-32 | error | 禁止双重类型转换 as Any as T 🆕 |

M-Level: Medium (Replace with Alternative) — 1 rule

| Rule | ID | Default | Description | |------|----|---------|-------------| | no-js-builtin-api | M-17, M-20~M-22 | error | 禁止直接调用 JS 内置 API (Object/Array/String/Math) 🆕 |

C-Level: Code Style (Best Practices) — 3 rules

| Rule | ID | Default | Description | |------|----|---------|-------------| | prefer-template-literal | C-04, R-14 | warn | 优先使用模板字符串拼接 🆕 | | no-nested-ternary | F-28, C-10 | error | 禁止嵌套三元表达式 🆕 | | class-member-order | R-12, C-09 | warn | 类成员遵循标准顺序 (Swift/Kotlin) 🆕 |

Rule Details

F-03~F-05: no-destructuring

检测所有形式的解构:

const { a, b } = obj;        // ❌ Object destructuring
const [x, y] = arr;          // ❌ Array destructuring
function foo({ name }) {}    // ❌ Parameter destructuring

Fix: 使用显式属性访问:

const a = obj.a;
const b = obj.b;
const x = arr[0];
function foo(param) { const name = param.name; }

F-06: no-object-spread

const merged = { ...obj1, ...obj2 };   // ❌

Fix: 使用 merge 工具函数:

const merged = merge(obj1, obj2);

F-07: no-index-signature

interface Dict {
  [key: string]: any;    // ❌ Index Signature
}

Fix: 使用显式字段或 Map:

interface Dict {
  name: string;
  value: number;
}

F-08~F-09: no-dynamic-property-access

const key = 'name';
obj[key] = value;       // ❌ dynamic key

Fix: 使用 Map 存储动态键值对:

const map = new Map<string, any>();
map.set(key, value);

F-21: no-nested-function

function outer() {
  function inner() {}     // ❌ nested function declaration
}

Fix: 提取到模块级别或使用箭头函数。


M-01: require-null-over-undefined

let x = undefined;        // ❌
if (x === undefined) {}   // ❌
return undefined;         // ❌

Fix: 统一使用 null

let x = null;
if (x == null) {}
return null;

M-07~M-12: no-web-api-direct

禁止直接调用必须通过抽象层的平台特定 API:

console.log('msg');              // ❌ use Logger from core/platform/logger.ts
requestAnimationFrame(cb);        // ❌ use getAnimationScheduler()
performance.now();                // ❌ use getAnimationScheduler().now()
setTimeout(fn, 100);              // ❌ use getAnimationScheduler().setTimeout()

Fix:core/platform/ 导入平台抽象模块。


M-04~M-05: no-weakmap-proxy

const wm = new WeakMap();        // ⚠️ warn: 各平台行为不一致
const p = new Proxy(target, {}); // ⚠️ warn: ArkTS 不支持

Fix: 使用 Map 替代 WeakMap;使用显式适配器类替代 Proxy


🆕 F-29: no-typeof-runtime-check

v2.0 新增规则 — 禁止使用 typeof 进行运行时类型检查:

if (typeof item === 'string') { ... }   // ❌
if (typeof obj === 'object') { ... }    // ❌

Fix: 使用类型守卫函数:

function isString(value: unknown): value is string {
  return typeof value === 'string';
}

function isObject(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null;
}

if (isString(item)) { ... }    // ✅
if (isObject(obj)) { ... }    // ✅

Auto-fix: ESLint 可自动将 typeof x === 'string' 转换为 isString(x)


🆕 F-30: no-object-as-map

v2.0 新增规则 — 禁止使用 JS 对象作为 Map:

const entries = Object.entries(obj);      // ❌ Kotlin/Swift 不存在
const newObj = Object.fromEntries(entries); // ❌ Kotlin/Swift 不存在
const keys = Object.keys(obj);            // ❌ 应使用 Map.keys()
const values = Object.values(obj);         // ❌ 应使用 Map.values()

Fix: 使用 Map 替代对象存储键值对:

const map = new Map<string, any>();
map.set('key', 'value');
const entries = Array.from(map.entries());

🆕 F-31: require-explicit-return-type

v2.0 新增规则 — 要求所有公开函数必须有显式返回类型注解:

function getData() {              // ❌ 隐式返回类型
  return { items: [] };
}

Fix: 添加显式返回类型:

function getData(): { items: Item[] } {  // ✅
  return { items: [] };
}

Strict Mode: 在 v4-production 配置中,箭头函数也必须显式声明返回类型。


🆕 F-32: no-double-type-cast

v2.0 新增规则 — 禁止双重类型转换:

const result = obj as Any as T;          // ❌ 完全丢失类型安全
const value = data as unknown as MyType;  // ❌

Fix: 使用单次安全转换或类型检查:

const result = obj as T;                  // ✅ 单次转换
const result2 = obj as? T;                 // ✅ 可选链转换
if (result !== null) { ... }               // ✅ 带检查

🆕 M-17, M-20~M-22: no-js-builtin-api

v2.0 新增规则 — 禁止直接调用需要平台映射的 JS 内置 API:

Object.entries(obj);           // ❌ 需映射为 map.entries()
Array.prototype.push.call(arr, item);  // ❌
str.includes(sub);             // ⚠️ 部分平台名称不同
Math.floor(x);                 // ⚠️ 平台差异

Fix: 参考 Safe TS Subset v4.0 API映射表

| JS API | Kotlin | Swift | |--------|--------|-------| | arr.push(item) | arr.add(item) | arr.append(item) | | arr.pop() | arr.removeAt(arr.size - 1) | arr.removeLast() | | Object.keys(obj) | (obj as Map<String, Any>).keys | (obj as! [String: Any]).keys |


🆕 C-04: prefer-template-literal

v2.0 新增规则 — 优先使用模板字符串拼接:

const str = "prefix_" + index + "_suffix";  // ❌

Fix:

const str = `prefix_${index}_suffix`;        // ✅

Auto-fix: ESLint 可自动将字符串拼接转换为模板字符串。


🆕 F-28: no-nested-ternary

v2.0 新增规则 — 禁止嵌套三元表达式:

const result = condition1 ? (condition2 ? value1 : value2) : value3;  // ❌

Fix: 使用 if-else 或提取变量:

let result: string;
if (condition1) {
  result = condition2 ? value1 : value2;
} else {
  result = value3;
}

🆕 C-09: class-member-order

v2.0 新增规则 — 强制类成员遵循 Swift/Kotlin 惯例顺序:

class BadOrder {
  render() { }           // ❌ 应在 constructor 后
  private _state;        // ❌ 应在最前
  constructor() { }      // ❌ 应在属性后
  
  dispose() { }          // ❌ 应在 constructor 后
  static VERSION = '1';  // ❌ 应在最前
}

Fix: 遵循标准顺序:

class GoodOrder {
  static readonly VERSION = '1.0.0';  // 1. 静态属性
  private _state;                    // 2. 实例属性
  
  constructor() { }                  // 3. 构造函数
  dispose() { }                      // 4. 生命周期方法
  
  render() { }                       // 5. 公共方法
  protected beforeRender() { }        // 6. 受保护方法
  private createInitialState() { }    // 7. 私有方法
}

Config Presets

recommended

平衡的严格度,适合大多数项目。所有规则为 error,部分规则为 warn

{
  extends: ['plugin:@qiun/ucharts/recommended']
}

strict

所有规则均为 error,适用于必须通过跨平台转译的代码:

{
  extends: ['plugin:@qiun/ucharts/strict']
}

v4-production 🆕

生产级最严格配置,适用于发布前最终质量门禁:

{
  extends: ['plugin:@qiun/ucharts/v4-production']
}

特点:

  • 扩展了 no-web-api-direct 的禁止列表(增加 setTimeout/setInterval/performance.measure)
  • 扩展了 no-js-builtin-api 的禁止列表(完整覆盖 Object/Array/String/Math API)
  • require-explicit-return-type 排除私有方法和箭头函数

Integration with VSCode

Settings

{
  "eslint.enable": true,
  "eslint.run": "onType",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  }
}

Auto-Fix Support

以下规则支持自动修复:

| Rule | Fix Example | |------|-------------| | no-typeof-runtime-check | typeof x === 'string'isString(x) | | no-double-type-cast | obj as Any as Tobj as T | | prefer-template-literal | "a" + b`a${b}` |


Integration with uCharts Project

Package.json Scripts

{
  "scripts": {
    "lint": "eslint . --ext .ts,.js",
    "lint:fix": "eslint . --fix",
    "lint:subset": "eslint core/ --ext .ts --rule 'plugin:@qiun/ucharts/strict'",
    "lint:v4": "eslint core/ --ext .ts --rule 'plugin:@qiun/ucharts/v4-production'",
    "check:subset": "npm run lint:v4 && echo '✅ Safe TS Subset v4.0 check passed!'"
  }
}

File Exemptions

对需要特殊处理的文件使用 overrides:

{
  files: ['core/util/merge.ts'],
  rules: {
    '@qiun/ucharts/no-dynamic-property-access': 'off',
    '@qiun/ucharts/no-index-signature': 'off',
    '@qiun/ucharts/no-object-as-map': 'off',
    '@qiun/ucharts/no-js-builtin-api': 'off'
  }
},
{
  files: ['core/util/type-guards.ts'],
  rules: {
    '@qiun/ucharts/no-typeof-runtime-check': 'off'
  }
},
{
  files: ['core/platform/**/*.ts'],
  rules: {
    '@qiun-ucharts/no-web-api-direct': 'off',
    '@qiun-ucharts/require-null-over-undefined': 'off',
    '@qiun-ucharts/no-js-builtin-api': 'off'
  }
}

Development

# Clone the uCharts repo
git clone https://github.com/qiun/ucharts.git
cd uCharts-v4

# Install dependencies
npm install

# Lint core/ with v4-production config
npm run lint:v4

# Generate violation report
npm run lint:subset:report

# Run with verbose output
npx eslint core/ --ext .ts -f stylish

Migration Guide (v1.0 → v2.0)

Breaking Changes

v2.0 完全向后兼容 v1.0。主要变化:

  1. 规则数量增加:10 → 18 条
  2. 新增配置预设v4-production
  3. 更严格的检查:新增 8 条规则覆盖 v4.0 规范

Quick Migration

# Update plugin
npm install @qiun/eslint-plugin-ucharts@latest

# Check violations
npm run lint:subset:report

Related Documents


License

Apache-2.0