From a2f8aa02bf772283e6bec379a61bc2a22543fdc7 Mon Sep 17 00:00:00 2001 From: mlight lee Date: Fri, 6 Mar 2026 16:44:04 +0800 Subject: [PATCH] feat: fix bugs on functions rgb2int and int2rgb --- .github/workflows/github-release.yml | 22 ++++++ .github/workflows/publish-npm.yml | 49 ++++++++++++ package.json | 7 +- src/parser.test.ts | 8 +- src/parser.ts | 6 +- tools/release.mjs | 107 +++++++++++++++++++++++++++ 6 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/github-release.yml create mode 100644 .github/workflows/publish-npm.yml create mode 100644 tools/release.mjs diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml new file mode 100644 index 0000000..3bcb762 --- /dev/null +++ b/.github/workflows/github-release.yml @@ -0,0 +1,22 @@ +name: Create GitHub release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + steps: + - name: Create GitHub release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + name: Release ${{ github.ref_name }} + generate_release_notes: true diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 0000000..b26357f --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,49 @@ +name: Publish packages to npm + +on: + push: + tags: + - 'v*' + workflow_dispatch: + +permissions: + contents: read + +jobs: + publish: + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Lint code + run: pnpm lint + + - name: Build package + run: pnpm build + + - name: Run tests + run: pnpm test + + - name: Publish package to npm + run: pnpm publish --no-git-checks --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/package.json b/package.json index 23b89d8..728c261 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mlightcad/mtext-parser", - "version": "1.3.2", + "version": "1.3.3", "description": "AutoCAD MText parser written in TypeScript", "type": "module", "main": "dist/parser.cjs.js", @@ -17,12 +17,13 @@ "build": "vite build", "build:example": "vite build --config vite.config.ts --mode example", "build:types": "tsc --emitDeclarationOnly", - "test": "jest", "example": "npm run build && npm run build:example && node dist/node/example.cjs.js", "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json}\"", "format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json}\"", "lint": "eslint ./src --ext .ts", - "lint:fix": "eslint ./src --ext .ts --fix" + "lint:fix": "eslint ./src --ext .ts --fix", + "release": "node tools/release.mjs", + "test": "jest" }, "keywords": [ "autocad", diff --git a/src/parser.test.ts b/src/parser.test.ts index 411f340..a9921a4 100644 --- a/src/parser.test.ts +++ b/src/parser.test.ts @@ -16,17 +16,17 @@ import { describe('Utility Functions', () => { describe('rgb2int', () => { it('converts RGB tuple to integer', () => { - expect(rgb2int([255, 0, 0])).toBe(0x0000ff); + expect(rgb2int([255, 0, 0])).toBe(0xff0000); expect(rgb2int([0, 255, 0])).toBe(0x00ff00); - expect(rgb2int([0, 0, 255])).toBe(0xff0000); + expect(rgb2int([0, 0, 255])).toBe(0x0000ff); }); }); describe('int2rgb', () => { it('converts integer to RGB tuple', () => { - expect(int2rgb(0x0000ff)).toEqual([255, 0, 0]); + expect(int2rgb(0xff0000)).toEqual([255, 0, 0]); expect(int2rgb(0x00ff00)).toEqual([0, 255, 0]); - expect(int2rgb(0xff0000)).toEqual([0, 0, 255]); + expect(int2rgb(0x0000ff)).toEqual([0, 0, 255]); }); }); diff --git a/src/parser.ts b/src/parser.ts index d656d54..cf1f22c 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -214,7 +214,7 @@ const CHAR_TO_ALIGN: Record = { */ export function rgb2int(rgb: RGB): number { const [r, g, b] = rgb; - return (b << 16) | (g << 8) | r; + return (r << 16) | (g << 8) | b; } /** @@ -223,9 +223,9 @@ export function rgb2int(rgb: RGB): number { * @returns RGB color tuple */ export function int2rgb(value: number): RGB { - const r = value & 0xff; + const r = (value >> 16) & 0xff; const g = (value >> 8) & 0xff; - const b = (value >> 16) & 0xff; + const b = value & 0xff; return [r, g, b]; } diff --git a/tools/release.mjs b/tools/release.mjs new file mode 100644 index 0000000..7462d3f --- /dev/null +++ b/tools/release.mjs @@ -0,0 +1,107 @@ +#!/usr/bin/env node +import { execSync } from 'node:child_process'; + +function run(cmd) { + return execSync(cmd, { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + }).trim(); +} + +function fail(msg) { + console.error(`❌ ${msg}`); + process.exit(1); +} + +/** + * Parse vX.Y.Z + */ +function parseVersion(tag) { + const m = tag.match(/^v(\d+)\.(\d+)\.(\d+)$/); + if (!m) return null; + return { + major: Number(m[1]), + minor: Number(m[2]), + patch: Number(m[3]), + }; +} + +/** + * Find latest vX.Y.Z tag (sorted by semver, not by time) + */ +function findLatestTag() { + const output = run('git tag --list "v*.*.*"'); + if (!output) return null; + + const tags = output + .split('\n') + .map(t => ({ tag: t, v: parseVersion(t) })) + .filter(t => t.v !== null); + + if (tags.length === 0) return null; + + tags.sort((a, b) => { + if (a.v.major !== b.v.major) return b.v.major - a.v.major; + if (a.v.minor !== b.v.minor) return b.v.minor - a.v.minor; + return b.v.patch - a.v.patch; + }); + + return tags[0].tag; +} + +/** + * Main + */ +let version = process.argv[2]; + +if (!version) { + const latestTag = findLatestTag(); + if (!latestTag) { + fail('No existing vX.Y.Z tag found, please specify a version explicitly.'); + } + + const v = parseVersion(latestTag); + version = `${v.major}.${v.minor}.${v.patch + 1}`; + + console.log(`ℹ️ No version provided, auto-incrementing patch: ${latestTag} → v${version}`); +} + +if (!/^\d+\.\d+\.\d+$/.test(version)) { + fail(`Invalid version "${version}". Expected format: X.Y.Z`); +} + +const tag = `v${version}`; + +/** + * Safety checks + */ +try { + run(`git rev-parse --verify refs/tags/${tag}`); + fail(`Tag ${tag} already exists.`); +} catch { + // tag does not exist → OK +} + +try { + const branch = run('git branch --show-current'); + if (branch !== 'main') { + fail(`Current branch is "${branch}". Please release from "main".`); + } +} catch { + // non-fatal +} + +const status = run('git status --porcelain'); +if (status) { + fail('Working tree is not clean. Please commit or stash changes.'); +} + +/** + * Create & push annotated tag + */ +console.log(`🚀 Creating tag ${tag}`); + +run(`git tag -a ${tag} -m "release: release ${tag}"`); +run(`git push origin ${tag}`); + +console.log(`✅ Release tag ${tag} pushed successfully`);