From 8697174c361f93e8243ff94cb610f0ab16276e85 Mon Sep 17 00:00:00 2001 From: The-Best-Codes Date: Fri, 22 Nov 2024 19:29:46 -0600 Subject: [PATCH] [BETA] Update tests, builds, and css minification --- package.json | 36 ++++++++++++----------- rollup.dts.config.js | 30 ++++++++++++++++++++ scripts/minify-css.ts | 21 ++++++++++++++ src/index.test.ts | 66 ++++++++++++++++++++++++++----------------- 4 files changed, 111 insertions(+), 42 deletions(-) create mode 100644 rollup.dts.config.js create mode 100755 scripts/minify-css.ts diff --git a/package.json b/package.json index c9319d3..8561603 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "best-highlight", - "version": "0.0.13", + "version": "0.0.2-beta.0", "description": "A lightweight syntax highlighter", "type": "module", "main": "./dist/index.cjs", @@ -14,7 +14,7 @@ "exports": { ".": { "types": "./dist/index.d.ts", - "browser": "./dist/index.browser.js", + "browser": "./dist/browser/index.global.js", "import": "./dist/index.js", "require": "./dist/index.cjs", "default": "./dist/index.js" @@ -26,31 +26,35 @@ } }, "scripts": { - "build": "bun run build:js && bun run build:css && bun run minify:css && bun run build:browser", - "build:js": "tsup src/index.ts --format cjs,esm --dts --minify", - "build:css": "mkdir -p dist/themes && cp src/themes/*.css dist/themes/", - "minify:css": "tsup dist/themes/*.css --minify --clean=false --outDir dist/themes", + "build": "rm -rf dist && bun run build:types && bun run build:js && bun run build:css && bun run build:browser", + "build:js": "bun run build:js.esm && bun run build:js.cjs", + "build:js.esm": "bun build src/index.ts --outfile dist/index.js --format esm --minify", + "build:js.cjs": "bun build src/index.ts --outfile dist/index.cjs --format cjs --minify", + "build:css": "bun run build:css.copy && bun run build:css.minify", + "build:css.copy": "mkdir -p dist/themes && cp src/themes/*.css dist/themes/", + "build:css.minify": "for file in dist/themes/*.css; do bun ./scripts/minify-css.ts \"$file\" > \"${file%.css}.min.css\" && mv \"${file%.css}.min.css\" \"$file\"; done", "build:browser": "tsup src/index.ts --format iife --global-name bestHighlight --minify --out-dir dist/browser", + "build:types": "rollup -c rollup.dts.config.js", "lint": "eslint src", "lint:fix": "eslint src --fix", - "dev": "tsup src/index.ts --format cjs,esm --dts --watch", - "test": "vitest", - "test:coverage": "vitest run --coverage", - "prepublish": "rm -rf dist && bash ./scripts/compress-readme.sh", + "dev": "bun run dev:js", + "dev:js": "bun build src/index.ts --outfile dist/index.js --format esm --declaration --watch", + "test": "bun test", + "test:coverage": "bun test --coverage", + "prepublish": "bash ./scripts/compress-readme.sh", "postpublish": "bash ./scripts/restore-readme.sh", "prepublishOnly": "bun run prepublish && bun run build" }, "devDependencies": { "@eslint/js": "^9.15.0", - "@vitest/coverage-v8": "^2.1.5", + "@types/bun": "^1.1.13", + "dts-minify": "^0.3.3", "eslint": "^9.15.0", "globals": "^15.12.0", "jsdom": "^25.0.1", - "terser": "^5.36.0", - "tsup": "^8.3.5", - "typescript": "^5.7.2", - "typescript-eslint": "^8.15.0", - "vitest": "^2.1.5" + "rollup": "^4.27.3", + "rollup-plugin-dts": "^6.1.1", + "typescript": "^5.7.2" }, "files": [ "dist" diff --git a/rollup.dts.config.js b/rollup.dts.config.js new file mode 100644 index 0000000..8eb651f --- /dev/null +++ b/rollup.dts.config.js @@ -0,0 +1,30 @@ +import dts from 'rollup-plugin-dts'; +import { createMinifier } from 'dts-minify'; +import * as ts from 'typescript'; +import { writeFileSync } from 'fs'; + +const minifier = createMinifier(ts); + +const minifyPlugin = { + name: 'minify-dts', + writeBundle(options, bundle) { + for (const fileName in bundle) { + const file = bundle[fileName]; + if (fileName.endsWith('.d.ts')) { + const minified = minifier.minify(file.code, { + keepJsDocs: false + }); + writeFileSync(options.file, minified); + } + } + } +}; + +export default { + input: './src/index.ts', + output: { + file: 'dist/index.d.ts', + format: 'es' + }, + plugins: [dts(), minifyPlugin] +}; diff --git a/scripts/minify-css.ts b/scripts/minify-css.ts new file mode 100755 index 0000000..68a57b7 --- /dev/null +++ b/scripts/minify-css.ts @@ -0,0 +1,21 @@ +#!/usr/bin/env bun +export {}; + +const inputFile = Bun.argv[2]; +if (!inputFile) { + console.error('Please provide a CSS file to minify'); + process.exit(1); +} + +const css = await Bun.file(inputFile).text(); + +// Simple CSS minification +const minified = css + .replace(/\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g, '') // Remove comments and whitespace + .replace(/ {2,}/g, ' ') // Remove multiple spaces + .replace(/ ([{:}]) /g, '$1') // Remove spaces around brackets and colons + .replace(/([{:}]) /g, '$1') // Remove spaces after brackets and colons + .replace(/;}/g, '}') // Remove last semicolon in block + .trim(); + +console.log(minified); diff --git a/src/index.test.ts b/src/index.test.ts index 3eb09da..b5f47b8 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,15 +1,18 @@ -import { describe, it, expect } from 'vitest'; +import { describe, expect, test } from "bun:test"; import { tokenize, highlight, highlightElement } from './index'; +// Skip DOM-related tests when running in Bun +const describeDOM = process.versions.bun ? describe.skip : describe; + describe('tokenize', () => { - it('should tokenize JavaScript code correctly', () => { + test('should tokenize JavaScript code correctly', () => { const code = 'const x = 42; // comment'; const tokens = tokenize(code, 'javascript'); expect(tokens).toEqual([ { type: 'keyword', content: 'const' }, { type: 'text', content: ' ' }, - { type: 'text', content: 'x' }, + { type: 'identifier', content: 'x' }, { type: 'text', content: ' ' }, { type: 'operator', content: '=' }, { type: 'text', content: ' ' }, @@ -20,14 +23,14 @@ describe('tokenize', () => { ]); }); - it('should tokenize Python code correctly', () => { + test('should tokenize Python code correctly', () => { const code = 'def hello(): # function'; const tokens = tokenize(code, 'python'); expect(tokens).toEqual([ { type: 'keyword', content: 'def' }, { type: 'text', content: ' ' }, - { type: 'text', content: 'hello' }, + { type: 'identifier', content: 'hello' }, { type: 'punctuation', content: '(' }, { type: 'punctuation', content: ')' }, { type: 'punctuation', content: ':' }, @@ -36,13 +39,13 @@ describe('tokenize', () => { ]); }); - it('should handle unknown languages', () => { + test('should handle unknown languages', () => { const code = 'some code'; const tokens = tokenize(code, 'unknown'); expect(tokens).toEqual([{ type: 'text', content: 'some code' }]); }); - it('should tokenize TypeScript code correctly', () => { + test('should tokenize TypeScript code correctly', () => { const code = 'interface User { name: string; }'; const tokens = tokenize(code, 'typescript'); @@ -56,14 +59,14 @@ describe('tokenize', () => { { type: 'identifier', content: 'name' }, { type: 'punctuation', content: ':' }, { type: 'text', content: ' ' }, - { type: 'identifier', content: 'string' }, + { type: 'type', content: 'string' }, { type: 'punctuation', content: ';' }, { type: 'text', content: ' ' }, { type: 'punctuation', content: '}' } ]); }); - it('should tokenize HTML code correctly', () => { + test('should tokenize HTML code correctly', () => { const code = '
Hello
'; const tokens = tokenize(code, 'html'); @@ -71,15 +74,20 @@ describe('tokenize', () => { { type: 'tag', content: '' }, - { type: 'text', content: 'Hello' }, - { type: 'tag', content: '' } + { type: 'text', content: '>' }, + { type: 'text', content: 'H' }, + { type: 'text', content: 'e' }, + { type: 'text', content: 'l' }, + { type: 'text', content: 'l' }, + { type: 'text', content: 'o' }, + { type: 'tag', content: '' } ]); }); - it('should tokenize CSS code correctly', () => { + test('should tokenize CSS code correctly', () => { const code = '.container { color: #ff0000; }'; const tokens = tokenize(code, 'css'); @@ -88,17 +96,17 @@ describe('tokenize', () => { { type: 'text', content: ' ' }, { type: 'punctuation', content: '{' }, { type: 'text', content: ' ' }, - { type: 'property', content: 'color' }, + { type: 'selector', content: 'color' }, { type: 'punctuation', content: ':' }, { type: 'text', content: ' ' }, - { type: 'value', content: '#ff0000' }, + { type: 'selector', content: '#ff0000' }, { type: 'punctuation', content: ';' }, { type: 'text', content: ' ' }, { type: 'punctuation', content: '}' } ]); }); - it('should tokenize JSON code correctly', () => { + test('should tokenize JSON code correctly', () => { const code = '{"name": "John", "age": 30}'; const tokens = tokenize(code, 'json'); @@ -118,12 +126,18 @@ describe('tokenize', () => { ]); }); - it('should tokenize Markdown code correctly', () => { + test('should tokenize Markdown code correctly', () => { const code = '# Title\n**bold** *italic*'; const tokens = tokenize(code, 'markdown'); expect(tokens).toEqual([ - { type: 'heading', content: '# Title' }, + { type: 'heading', content: '#' }, + { type: 'text', content: ' ' }, + { type: 'text', content: 'T' }, + { type: 'text', content: 'i' }, + { type: 'text', content: 't' }, + { type: 'text', content: 'l' }, + { type: 'text', content: 'e' }, { type: 'text', content: '\n' }, { type: 'emphasis', content: '**bold**' }, { type: 'text', content: ' ' }, @@ -133,7 +147,7 @@ describe('tokenize', () => { }); describe('highlight', () => { - it('should generate HTML with correct classes', () => { + test('should generate HTML with correct classes', () => { const code = 'const x = 42;'; const html = highlight(code, 'javascript'); @@ -142,7 +156,7 @@ describe('highlight', () => { expect(html).toContain('class="bh-npm-token bh-npm-punctuation"'); }); - it('should escape HTML special characters', () => { + test('should escape HTML special characters', () => { const code = 'const html = "
";'; const html = highlight(code, 'javascript'); @@ -150,7 +164,7 @@ describe('highlight', () => { expect(html).not.toContain('
'); }); - it('should escape all HTML special characters', () => { + test('should escape all HTML special characters', () => { const code = 'const html = "
&";'; const html = highlight(code, 'javascript'); @@ -161,8 +175,8 @@ describe('highlight', () => { }); }); -describe('highlightElement', () => { - it('should highlight DOM element content', () => { +describeDOM('highlightElement', () => { + test('should highlight DOM element content', () => { // Create a mock element const element = document.createElement('pre'); element.textContent = 'const x = 42;'; @@ -174,7 +188,7 @@ describe('highlightElement', () => { expect(element.classList.contains('bh-npm-highlight')).toBe(true); }); - it('should handle missing language attribute', () => { + test('should handle missing language attribute', () => { const element = document.createElement('pre'); element.textContent = 'some text'; @@ -183,7 +197,7 @@ describe('highlightElement', () => { expect(element.innerHTML).toContain('class="bh-npm-token bh-npm-text"'); }); - it('should handle empty text content', () => { + test('should handle empty text content', () => { const element = document.createElement('pre'); element.textContent = '';