Skip to content

Modernize project structure to 2025 Node.js best practices#39

Closed
Copilot wants to merge 3 commits intomainfrom
copilot/setup-hexo-asciidoc-plugin
Closed

Modernize project structure to 2025 Node.js best practices#39
Copilot wants to merge 3 commits intomainfrom
copilot/setup-hexo-asciidoc-plugin

Conversation

Copy link

Copilot AI commented Nov 17, 2025

Restructures the codebase following clean architecture principles with updated tooling for Node.js 24 LTS and modern development workflows.

Architecture Changes

  • Separate concerns: src/core/ (pure AsciiDoc logic) → src/hexo/ (Hexo adapter)
  • Collocate tests: test/src/__tests__/ for better discoverability
  • Type definitions: Split types between core domain (src/core/types.ts) and Hexo integration (src/types.ts)
// Before: mixed concerns in src/lib/renderer.ts
import asciidoctor from 'asciidoctor';
import hexoUtil from 'hexo-util';
const renderer = (data) => { /* Hexo + AsciiDoc + highlighting logic */ }

// After: layered separation
// src/core/convert.ts - pure conversion
export function convertAsciidoc(source: string, options: AsciidocOptions): string

// src/hexo/registerRenderer.ts - Hexo integration
export function registerAsciidocRenderer(hexo: Hexo): void

Configuration Updates

  • Node.js: >=20.0.0 with CI matrix for 20.x/22.x/24.x, .mise.toml defaults to 24
  • Package manager: pnpm@9.0.0 minimum (currently using 10.x)
  • Biome: lineWidth 100 (was 120)
  • TypeScript: Added tsconfig.build.json to exclude tests from compilation

Developer Experience

  • Example site: examples/basic-hexo-site/ with sample AsciiDoc posts demonstrating plugin features
  • Scripts: Reordered for logical workflow (preparebuildtestcheck)
  • Documentation: Updated README with architecture diagram and structure rationale

No breaking changes—maintains full backward compatibility with existing Hexo sites.

Original prompt

下面这套就是“可以直接开干”的最终方案:Node LTS + PNPM + Biome + TypeScript,专门针对「Hexo AsciiDoc 渲染器插件」。


一、技术栈定稿

运行环境(给用户用):

  • Node:24.x LTS 优先,兼容 Node ≥20

  • Hexo:建议对 Hexo 8+ 做适配(插件用 peerDependency 声明)

开发工具:


二、目录结构(最终版)

hexo-renderer-asciidoc/
  src/
    index.ts                  # 插件入口(给 Hexo 调用)
    hexo/
      registerRenderer.ts     # Hexo 适配层(只依赖 Hexo)
    core/
      convert.ts              # AsciiDoc -> HTML 纯函数
      options.ts              # 处理和规范化配置
      types.ts                # 公共类型定义
    __tests__/
      convert.spec.ts
      hexo.integration.spec.ts
  examples/
    basic-hexo-site/          # demo 站点,验证插件
  dist/                        # 构建输出目录(git 忽略)
  package.json
  pnpm-lock.yaml
  tsconfig.json
  tsconfig.build.json
  biome.json
  vitest.config.ts
  README.md
  CHANGELOG.md (可选,配合 release 工具)

原则:

  • core/ 不依赖 Hexo,方便单测和复用

  • hexo/ 只做“接 Hexo”那一层

  • src/index.ts 是真正的包入口,导出给 Hexo


三、关键配置文件(可直接拷)

1. package.json

{
  "name": "hexo-renderer-asciidoc",
  "version": "0.1.0",
  "description": "AsciiDoc renderer plugin for Hexo (TypeScript, Biome, Vitest)",
  "license": "MIT",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": [
    "dist"
  ],
  "keywords": [
    "hexo",
    "hexo-plugin",
    "hexo-renderer",
    "asciidoc",
    "asciidoctor"
  ],
  "engines": {
    "node": ">=20.0.0"
  },
  "peerDependencies": {
    "hexo": ">=8.0.0"
  },
  "dependencies": {
    "asciidoctor": "^3.0.4"
  },
  "devDependencies": {
    "@biomejs/biome": "^1.9.0",
    "@types/hexo": "^3.0.0",
    "typescript": "^5.6.0",
    "vitest": "^2.0.0"
  },
  "scripts": {
    "prepare": "pnpm build",
    "build": "tsc -p tsconfig.build.json",
    "typecheck": "tsc --noEmit",
    "test": "vitest run",
    "test:watch": "vitest",
    "lint": "biome lint .",
    "format": "biome format . --write",
    "check": "biome check .",
    "prepublishOnly": "pnpm build && pnpm test && pnpm check"
  },
  "packageManager": "pnpm@9.0.0"
}

peerDependencies.hexo 保证插件复用宿主项目的 Hexo 实例,不会装多份 Hexo。


2. TypeScript 配置

tsconfig.json(开发 / 类型检查)

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "lib": ["ES2020"],
    "moduleResolution": "Node10",
    "rootDir": "src",
    "outDir": "dist",
    "declaration": true,
    "declarationMap": true,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true
  },
  "include": ["src", "vitest.config.ts"]
}

tsconfig.build.json(构建专用)

{
  "extends": "./tsconfig.json",
  "exclude": ["src/__tests__/**/*", "**/*.spec.ts"]
}

3. Biome 配置:biome.json

按官方推荐用 JSON 配置,统一 Format + Lint + import 排序。Biome+3Biome+3Biome+3

{
  "$schema": "https://biomejs.dev/schemas/latest/schema.json",
  "formatter": {
    "enabled": true,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "organizeImports": {
    "enabled": true
  },
  "files": {
    "include": ["src/**/*.ts", "vitest.config.ts"],
    "ignore": ["dist/**", "examples/**"]
  }
}

VS Code 装官方 Biome 插件之后,保存时就能自动 format + lint。Biome


4. Vitest 配置:vitest.config.ts

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    include: ['src/__tests__/**/*.spec.ts'],
    globals: true
  }
});

四、核心代码骨架

1. 插件入口:src/index.ts

Hexo 在加载插件时会执行这个导出函数,把 Hexo 实例丢进来。Hexo+1

import type Hexo from 'hexo';
import { registerAsciidocRenderer } from './hexo/registerRenderer';

export = (hexo: Hexo): void => {
  registerAsciidocRenderer(hexo);
};

注意这里用了 export =,配合 module: "CommonJS",编译后就是 module.exports = function (hexo) { ... },Hexo 直接 require('hexo-renderer-asciidoc') 就能用。


2. ...

Created from VS Code via the GitHub Pull Request extension.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@semanticdiff-com
Copy link

semanticdiff-com bot commented Nov 17, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  .prettierrc.mjs  100% smaller
  .vscode/settings.json  100% smaller
  tsdown.config.cjs  100% smaller
  biome.json  98% smaller
  package.json  80% smaller
  scripts/npm-readme.cjs  78% smaller
  src/__tests__/index.test.ts  75% smaller
  vitest.config.ts  57% smaller
  src/__tests__/helpers/render.ts  50% smaller
  src/core/convert.ts  16% smaller
  tsconfig.json  7% smaller
  src/index.ts  4% smaller
  .github/workflows/ci.yml  1% smaller
  .gitignore Unsupported file format
  .mise.toml Unsupported file format
  README.md Unsupported file format
  examples/basic-hexo-site/README.md Unsupported file format
  examples/basic-hexo-site/_config.yml  0% smaller
  examples/basic-hexo-site/package.json  0% smaller
  examples/basic-hexo-site/source/_posts/advanced-features.adoc Unsupported file format
  examples/basic-hexo-site/source/_posts/hello-asciidoc.adoc Unsupported file format
  src/__tests__/doctest/__snapshots__/admonition.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/audio.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/colist.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/dlist.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/document.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/embedded.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/example.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/floating_title.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/image.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_anchor.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_break.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_button.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_callout.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_footnote.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_image.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_kbd.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_menu.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/inline_quoted.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/listing.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/literal.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/olist.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/open.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/outline.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/page_break.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/paragraph.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/pass.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/preamble.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/quote.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/section.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/sidebar.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/stem.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/table.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/thematic_break.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/toc.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/ulist.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/verse.test.ts.snap Unsupported file format
  src/__tests__/doctest/__snapshots__/video.test.ts.snap Unsupported file format
  src/__tests__/doctest/admonition.test.ts  0% smaller
  src/__tests__/doctest/audio.test.ts  0% smaller
  src/__tests__/doctest/colist.test.ts  0% smaller
  src/__tests__/doctest/dlist.test.ts  0% smaller
  src/__tests__/doctest/document.test.ts  0% smaller
  src/__tests__/doctest/embedded.test.ts  0% smaller
  src/__tests__/doctest/example.test.ts  0% smaller
  src/__tests__/doctest/examples/asciidoc/admonition.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/audio.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/colist.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/dlist.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/document.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/embedded.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/example.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/floating_title.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/image.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_anchor.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_break.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_button.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_callout.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_footnote.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_image.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_kbd.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_menu.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/inline_quoted.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/listing.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/literal.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/olist.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/open.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/outline.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/page_break.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/paragraph.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/pass.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/preamble.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/quote.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/section.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/sidebar.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/stem.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/table.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/thematic_break.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/toc.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/ulist.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/verse.adoc Unsupported file format
  src/__tests__/doctest/examples/asciidoc/video.adoc Unsupported file format
  src/__tests__/doctest/floating_title.test.ts  0% smaller
  src/__tests__/doctest/image.test.ts  0% smaller
  src/__tests__/doctest/inline_anchor.test.ts  0% smaller
  src/__tests__/doctest/inline_break.test.ts  0% smaller
  src/__tests__/doctest/inline_button.test.ts  0% smaller
  src/__tests__/doctest/inline_callout.test.ts  0% smaller
  src/__tests__/doctest/inline_footnote.test.ts  0% smaller
  src/__tests__/doctest/inline_image.test.ts  0% smaller
  src/__tests__/doctest/inline_kbd.test.ts  0% smaller
  src/__tests__/doctest/inline_menu.test.ts  0% smaller
  src/__tests__/doctest/inline_quoted.test.ts  0% smaller
  src/__tests__/doctest/listing.test.ts  0% smaller
  src/__tests__/doctest/literal.test.ts  0% smaller
  src/__tests__/doctest/olist.test.ts  0% smaller
  src/__tests__/doctest/open.test.ts  0% smaller
  src/__tests__/doctest/outline.test.ts  0% smaller
  src/__tests__/doctest/page_break.test.ts  0% smaller
  src/__tests__/doctest/paragraph.test.ts  0% smaller
  src/__tests__/doctest/pass.test.ts  0% smaller
  src/__tests__/doctest/preamble.test.ts  0% smaller
  src/__tests__/doctest/quote.test.ts  0% smaller
  src/__tests__/doctest/runner.ts  0% smaller
  src/__tests__/doctest/section.test.ts  0% smaller
  src/__tests__/doctest/sidebar.test.ts  0% smaller
  src/__tests__/doctest/stem.test.ts  0% smaller
  src/__tests__/doctest/table.test.ts  0% smaller
  src/__tests__/doctest/thematic_break.test.ts  0% smaller
  src/__tests__/doctest/toc.test.ts  0% smaller
  src/__tests__/doctest/ulist.test.ts  0% smaller
  src/__tests__/doctest/verse.test.ts  0% smaller
  src/__tests__/doctest/video.test.ts  0% smaller
  src/core/options.ts  0% smaller
  src/core/types.ts  0% smaller
  src/global.d.ts  0% smaller
  src/hexo/registerRenderer.ts  0% smaller
  src/types.ts  0% smaller
  tsconfig.build.json  0% smaller

Copilot AI and others added 2 commits November 17, 2025 07:19
- Update Node.js engine requirement to >=20.0.0
- Update packageManager to pnpm@9.0.0
- Restructure source code: src/lib → src/core and add src/hexo layer
- Move tests from test/ to src/__tests__/
- Update biome.json lineWidth to 100
- Add tsconfig.build.json for build-specific configuration
- Update CI to test Node 20.x, 22.x, 24.x
- Update .mise.toml to prioritize Node 24.x
- Reorder package.json scripts for better workflow
- Fix all Biome linting issues
- All tests passing (246 tests)

Co-authored-by: hcoona <712433+hcoona@users.noreply.github.com>
- Create examples/basic-hexo-site with sample AsciiDoc posts
- Add comprehensive README for the example site
- Update .gitignore to exclude example artifacts
- Update main README to document new project structure
- Add examples section to README

The example demonstrates:
- Basic AsciiDoc features (lists, code, tables, admonitions)
- Advanced features (cross-refs, math, callouts, quotes, sidebars)
- Configuration via _config.yml
- Multiple AsciiDoc file extensions (.adoc)

Co-authored-by: hcoona <712433+hcoona@users.noreply.github.com>
Copilot AI changed the title [WIP] Setup Hexo AsciiDoc renderer plugin with Node LTS Modernize project structure to 2025 Node.js best practices Nov 17, 2025
Copilot AI requested a review from hcoona November 17, 2025 07:28
@hcoona hcoona closed this Nov 17, 2025
@hcoona hcoona deleted the copilot/setup-hexo-asciidoc-plugin branch November 23, 2025 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants