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

@owocow/industries

v0.0.2

Published

Versioned two-level customer industry catalog with JSON data and typed lookup utilities

Downloads

210

Readme

@owocow/industries

两级客户行业目录,包含 20 个一级行业、114 个二级行业。提供静态数据、浏览器兼容的 ESM 查询方法和只读 TypeScript 类型,零运行时依赖,不绑定 UI 框架。

行业目录由 npm 包维护,前端直接导入。每个客户只保存一个二级行业 industry_code,如 ai_agent;名称和完整路径由本包解析。null 表示未设置。一级 code 和数字 id 不作为客户的行业值。

安装

npm install --save-exact @owocow/[email protected]

上述命令适用于包已发布的情况。发布前可在本项目执行 npm pack,然后在消费项目安装生成的本地包:

npm install /absolute/path/to/owocow-industries-0.0.1.tgz

主入口为 ESM,支持 import,不提供 CommonJS require 入口。构建和验证环境使用 Node.js 22 或以上版本。

通过 code 获取名称

import { getIndustryName } from '@owocow/industries'

// 默认只获取本节点名称。
getIndustryName('ai_agent')
// 'AI Agent'

// 获取一级行业到本节点的完整路径。
getIndustryName('ai_agent', { fullPath: true })
// '人工智能·AI / AI Agent'

// 自定义路径分隔符。
getIndustryName('ai_agent', { fullPath: true, separator: ' → ' })
// '人工智能·AI → AI Agent'

getIndustryName('ai') // '人工智能·AI'
getIndustryName('unknown') // ''
getIndustryName('') // ''
getIndustryName(null) // ''
getIndustryName() // ''

方法签名:

getIndustryName(code?: string | null, options?: IndustryNameOptions): string

interface IndustryNameOptions {
  readonly fullPath?: boolean // 默认 false
  readonly separator?: string // 完整路径默认用 ' / ' 连接
}

separator 仅在 fullPath: true 时生效,可以传空字符串。一级 code 的完整路径就是该一级名称。停用节点仍可以解析名称及完整路径,便于展示已有客户。

一级名称内部使用 · 连接并列领域,例如 人工智能·AI、教育·知识服务、影视·短剧·动漫;完整路径默认使用 / 分隔层级,例如 教育·知识服务 / 学校。也可通过 separator 自定义层级分隔符。

行业选择器

使用 getIndustryTree() 获取按排序排列的两级目录,只允许选择二级节点。选择器将 code 作为值、name 作为标签:

import {
  getIndustryTree, isSelectableIndustry,
  type SecondaryIndustryCode,
} from '@owocow/industries'

// 返回节点包含 id/code/name/sort/enabled,一级节点包含 children。
const industryOptions = getIndustryTree().map(parent => ({
  value: parent.code,
  label: parent.name,
  children: parent.children.map(child => ({
    value: child.code,
    label: child.name,
  })),
}))

// 两级选择器选中的路径;提交时取最后一级 code。
const selectedPath: string[] = ['ai', 'ai_agent']
const code = selectedPath.at(-1)
if (!isSelectableIndustry(code)) {
  throw new Error('请选择一个有效的二级行业')
}

// 客户请求中只传 code,字段命名按项目现有约定。
const payload = { industry_code: code }
const typedCode: SecondaryIndustryCode = 'ai_agent'

默认隐藏停用节点及停用一级下的全部子级;无有效子级的一级也不显示。isSelectableIndustry 对一级、未知或停用 code 返回 false。目录与查询结果均为只读数据,组件需要修改选项时可像上面一样映射出自己的对象。

客户列表与详情展示

假设客户接口返回 industry_code,可直接解析为名称:

import { getIndustryName } from '@owocow/industries'

const customer = { industry_code: 'ai_agent' }

// 列表中显示简短名称。
const listLabel = getIndustryName(customer.industry_code) || '未设置'
// 'AI Agent'

// 详情中显示完整路径。
const detailLabel = getIndustryName(customer.industry_code, {
  fullPath: true,
  separator: ' → ',
}) || '未设置'
// '人工智能·AI → AI Agent'

空值和未知 code 都返回 ''。如果页面需要区分“未设置”和“当前包版本无法识别”,可以分别处理:

const code = customer.industry_code
const label = code ? getIndustryName(code) || `未知行业(${code})` : '未设置'

客户列表筛选

二级行业筛选使用该节点的 code,例如 ai_agent。选择器沿用上述两级目录;筛选请求传 code,显示标签由 getIndustryName 生成。

如果页面需要按一级行业筛选,可从本包取得其全部二级 code:

import { getChildren } from '@owocow/industries'

const industryCodes = getChildren('ai', { includeDisabled: true })
  .map(node => node.code)

包含停用 code 可以覆盖历史客户。getChildren 对未知或二级 code 返回 [],调用页面应处理空结果。industryCodes 只是前端计算出的编码列表;是否支持多 code 筛选、请求字段名和查询逻辑由客户接口另行约定。

前端缓存

目录随 npm 包和前端构建产物发布,直接使用包导出的查询方法即可。当前数据不需要额外的目录请求、localStorage 或 IndexedDB 缓存。

包的主模块在同一个 JavaScript 模块环境中初始化一次,建立 code 与父子关系的内存索引;各页面导入的 getIndustryName 等方法复用这些索引。查询名称时直接调用,不要在每一行或每次渲染时重新执行 createIndustryCatalog。

  • 全局树形数据:直接复用 getIndustryTree() 返回的只读结果。
  • UI 组件专用选项:按上面的映射生成,可放在组件模块或框架的计算属性中复用。
  • 客户详情名称:根据 industry_code 直接查询,无需另外缓存名称。
  • 更新目录:升级 npm 包、提交锁文件并重新构建部署前端。已部署页面不会因 npm 发布而自动更新目录。

如果在多个窗口、Worker 或多份构建中加载本包,各自拥有独立的模块实例。无需将查询结果跨环境持久化。

全部导出

| 导出 | 行为 | | --- | --- | | getIndustryName(code, options?) | 默认返回本节点名称;fullPath: true 返回完整路径,默认分隔符为 /;未知值返回 '' | | getIndustry(code) | 精确编码查找,返回节点,未知值返回 undefined;保留停用节点 | | getIndustryTree(options?) | 默认返回可选目录;includeDisabled: true 返回完整树 | | getChildren(parentCode, options?) | 默认只返回有效二级节点;未知或二级 code 返回 [] | | getIndustryPath(code) | 返回一级到目标节点的节点数组;未知值返回 [] | | formatIndustryPath(code, separator?) | 返回完整路径字符串,默认分隔符为 →;未知值返回 '' | | isSelectableIndustry(code) | 仅在二级自身和父级同时启用时返回 true | | createIndustryCatalog(tree) | 校验并复制一份目录,返回相同查询 API,包含 getIndustryName | | industryTree | 完整只读树,包含停用节点 | | industryFlat | 全部 134 个只读节点;包含 level、parentCode、parentName | | catalogVersion / schemaVersion | 当前包的目录版本 / JSON 结构版本(当前结构版本为 1) |

TypeScript 导出:

  • 编码类型:IndustryCode、PrimaryIndustryCode、SecondaryIndustryCode。
  • 节点类型:IndustryBase、IndustryLeaf、IndustryCategory、PrimaryIndustry、SecondaryIndustry、FlatIndustry。
  • 查询类型:IndustryCatalog、IndustryQueryOptions、IndustryNameOptions。

编码联合类型对应安装版本的静态目录。查询方法接受 string | null | undefined,方便直接解析接口字段;空值不会匹配任何节点。

所有目录及查询结果均被冻结。节点按 sort 升序排列,同序按 id 排列。父级停用时,扁平数据的子级 enabled 也为 false,完整树保留源节点的独立开关。

可选:为自己的目录创建查询对象

通常使用包主入口的静态目录即可。如需处理另一份本地目录,可以使用工厂:

import { createIndustryCatalog, industryTree } from '@owocow/industries'

const catalog = createIndustryCatalog(industryTree)
catalog.getIndustryName('ai_agent') // 'AI Agent'
catalog.getIndustryName('ai_agent', { fullPath: true })
catalog.getIndustryTree()

工厂校验、复制、排序并冻结输入,不持有传入节点的引用。非法目录抛出 TypeError。工厂用于显式创建独立目录,普通页面查询无需调用它。

JSON 数据

发布包也包含可独立读取的 JSON 子路径:

import tree from '@owocow/industries/industry-tree.json' with { type: 'json' }
import flat from '@owocow/industries/industry-flat.json' with { type: 'json' }
import mapping from '@owocow/industries/industry-mapping.json' with { type: 'json' }
import meta from '@owocow/industries/catalog-meta.json' with { type: 'json' }
  • industry-tree.json:一级节点包含 children 的完整数组。
  • industry-flat.json:所有一级、二级节点;一级的 parentCode/parentName 为 null,二级包含父级信息,enabled 为有效状态。
  • industry-mapping.json:一级 code 到二级 code 数组的完整映射,包含停用节点,用于一级行业筛选与统计。
  • catalog-meta.json:catalogVersion、schemaVersion、primaryCount、secondaryCount、sourceSha256。

对应实体文件在包的 dist/ 中。JSON 字符编码为 UTF-8;JSON 模块导入语法的支持取决于消费方工具链。浏览器项目优先使用主入口的查询方法。

后端参数配置用的行业映射

dist/industry-mapping.json 从 data/industries.json 自动生成,不单独维护。它只包含 code 及归属关系,没有名称、id 或启用状态。包含 20 个一级 code,每个二级 code 恰好出现一次,共 114 个。停用一级及停用二级也保留映射,供历史客户筛选与统计使用。

以下是文件中 ai 的完整条目,其余一级行业采用相同结构:

{
  "ai": [
    "ai_generative",
    "ai_agent",
    "ai_large_model",
    "ai_application",
    "ai_infrastructure",
    "ai_data_service",
    "ai_smart_hardware"
  ]
}

可以把完整文件内容写入后端参数 industry_mapping。后端加载参数后解析并缓存:

  • 一级筛选:取对应二级 code 数组,作为客户 industry_code IN (...) 的条件。
  • 一级统计:建立“二级 code → 一级 code”的反向映射,将数据库按二级 code 分组的计数归并到一级。
  • 无效一级 code 应返回参数错误;未设置和无法识别的客户 code 单独计数,避免漏计。

客户表仍只保存二级 industry_code。映射是完整归属数据,不能用来判断新客户可选行业;选择校验使用 isSelectableIndustry 或目录中的启用状态。

Node.js 也可以通过包子路径获取配置文本:

import mapping from '@owocow/industries/industry-mapping.json' with { type: 'json' }

const configValue = JSON.stringify(mapping)
const aiCodes = mapping.ai

更新目录后重新构建本包,并同步后端参数及其缓存,保持前后端的 code 归属一致。

维护与验证

npm ci
npm run verify
npm run pack:check
npm pack

verify 构建并校验数据、运行 Node 测试和 TypeScript 类型检查。pack:check 创建真实 tarball,安装进临时项目并校验主入口方法、JSON 子路径及类型声明。prepack 和 prepublishOnly 都运行完整验证。

行业数据的唯一维护文件为 data/industries.json。dist/ 自动生成,不手工修改。构建失败会清除旧产物,防止打包陈旧数据。sourceSha256 是原始目录解析后 JSON.stringify 内容的 SHA-256,而非格式化文件字节的摘要。

编码与版本约定

  • 保留既有 code、id 及父级关系;code 最多 100 字符,仅使用小写字母、数字和下划线。不要通过数字 id 推算父级。
  • 名称修正与停用保留原编码;新增节点使用新 code/id。编码不能改含义或复用,停用后仍保留节点供已有客户展示。
  • 归属调整、合并和拆分使用新编码并另行处理已有客户的迁移。
  • data/releases/ 中的既有身份基线不修改或删除。构建检查这些基线,拒绝旧编码缺失、重编号或换父级。
  • 发布新版本时更新 package.json 及锁文件,保留旧基线;新增身份基线只包含审核后节点的 id/code/parentCode。
  • 名称修正或停用建议使用 patch,兼容新增使用 minor,结构/API 破坏性变更使用 major。消费者固定版本并提交锁文件。

本包只包含通用行业定义与查询工具,不包含客户数据。行业目录不属于官方统计分类标准。