SuperAPI AI 工具集

loom-javascript

编程与开发

查看项目

更新于 10-19 03:16

技能介绍

【用途】 本技能面向已掌握 JavaScript 基础的开发者,提供在 Node.js 22+(或 Bun)上编写符合惯例、可用于生产的 ES2022+ JavaScript 代码的决策规则和易被忽略的缺陷点,无需 TypeScript 构建步骤即可获得类型检查。TypeScript 语法由 loom-typescript 覆盖。

【工具链】 使用仓库锁文件指定的包管理器,新项目优先使用 Bun:安装用 bun install,添加依赖用 bun add(如 bun add zod,开发依赖 bun add -d vitest),运行脚本用 bun run build,一次性工具用 bunx eslint .,类型检查用 bunx tsc --noEmit,格式化为 bunx biome format --write . 或 bunx prettier --write .,依赖审计用 bun audit。锁文件 bun.lock 需提交,CI 中使用 bun install --frozen-lockfile。在 package.json 的 engines 字段和 .nvmrc 或 .tool-versions 中固定 Node 版本(>=22)。Lint 可选 ESLint 9(扁平配置 eslint.config.js,eslintrc* 为旧格式)或 Biome(biome.json,同时承担 Lint 与格式化),每个仓库只选一种。检测浮动 Promise 需在 jsconfig.json 中为 parserOptions.projectService 提供类型信息,方可启用 @typescript-eslint/no-floating-promises。

【模块系统】 package.json 含 "type": "module" 时为 ESM,.mjs 始终 ESM,.cjs 始终 CommonJS。ESM 使用 import/export,静态提升,支持顶层 await;__dirname/__filename 不存在,改用 import.meta.dirname 与 import.meta.filename(Node 20.11+);相对路径必须带扩展名;导入 JSON 需 with { type: "json" }。内置模块统一加 node: 前缀。优先具名导出。ESM 可自由导入 CommonJS,反向在 Node 22.12+ 无顶层 await 时可用 require() 加载,否则用 await import()。对外发布的包应声明 exports 映射。

【语言规则与集合】 始终使用 ===/!==,唯一例外是 value == null;用 Number.isNaN 而非与 NaN 比较;用 ?? 替代 || 处理 0、空字符串等假值;超出安全整数的 ID 及金额用 BigInt。默认 const,需重新赋值才用 let,不用 var。箭头函数用于回调,依赖 this 的方法需绑定。动态键场景优先 Map/Set,字典对象用 Object.create(null) 或 Object.hasOwn。不可变数组操作用 toSorted/toReversed/toSpliced/with;排序必须传比较函数。for...in 会遍历继承属性,改用 for...of 配合 Object.keys/entries;forEach 忽略回调中的 await。

【异步与错误】 async 函数始终返回 Promise,未处理的拒绝会导致 Node 崩溃。每个异步调用都应被 await、return 或用 .catch 显式分离。循环中 await 会串行化,独立任务用 Promise.all 并限制并发;Promise.all 首个失败即拒绝,allSettled 等待全部,any 取首个成功,race 取首个结果。try 内需 return await 才能捕获拒绝。用 util.promisify 或 node:fs/promises 等封装回调 API。取消操作传 AbortSignal(如 AbortSignal.timeout)。抛出 Error 对象而非字符串,包装时用 cause 传递原始错误;对可分支条件使用 Error 子类。fetch 在 4xx/5xx 时仍 resolve,需检查 res.ok。禁止空 catch。进程级 unhandledRejection 仅用于记录日志并以非零码退出。

【事件循环与 Node API】 同步长循环会阻塞所有请求,CPU 密集任务移至 worker_threads 或子进程;请求处理中避免 *Sync 文件与加密调用。流处理用 node:stream/promises 的 pipeline,for await 可处理背压。文件、路径、HTTP、加密、子进程、CLI 参数(util.parseArgs)、配置(--env-file)、测试(node:test)、并发与请求上下文(AsyncLocalStorage)均使用对应 node: 内置模块。子进程使用 execFile 传参数数组,避免 shell 注入。

【无 TypeScript 的类型】 JSDoc 配合 // @ts-check 可获得与 .ts 相同的编辑器与 tsc 检查,在 jsconfig.json/tsconfig.json 中开启 allowJs、checkJs、strict,CI 执行 bunx tsc --noEmit。跨文件类型可放 types.d.ts 或用 @import 导入。外部输入仍需运行时校验(zod、valibot 或手写守卫),JSDoc 类型在运行时不存在。

【模块与 API 设计】 一个模块一个职责,导出最小接口;避免导入时副作用,导出 createX(options) 工厂由入口组装依赖;依赖(时钟、fetch、logger、数据库)通过参数注入以便测试;在边界处校验,内部信任已校验的结构。

【常见陷阱】 不可信 JSON 合并需过滤 proto/constructor/prototype 防原型污染;数字默认值用 ?? 以免丢失 0;forEach 中 async 需改为 Promise.all(items.map(...));嵌套量词正则存在 ReDoS 风险,需限制输入长度;模板字符串拼接 HTML/SQL/shell 是注入点,应用转义库、参数化查询和 execFile;密钥比较用 crypto.timingSafeEqual,令牌用 crypto.randomBytes 或 randomUUID 而非 Math.random。安装依赖前审查新包并运行 bun audit。

【测试】 运行器选择:node:test 零依赖适合纯 Node 代码;bun test 适合 Bun 项目;Vitest 适合 Vite 或 ESM 优先项目;Jest 适合既有测试套件。测试应一个失败原因、名称描述行为;异步测试需 await 或返回 Promise;拒绝断言用 assert.rejects 而非 try/catch;用运行器假时钟并在 afterEach 恢复。