From f851d39ea1239aa19ac0657527702f30df837d6e Mon Sep 17 00:00:00 2001 From: emahiro Date: Tue, 24 Jun 2025 23:45:16 +0900 Subject: [PATCH] feat: create microcms-rich-parser npm library with modern blog styling and dark mode support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- design/microcms-rich-editor-modern-parser.md | 17 + microcms-rich-parser/.npmignore | 8 + microcms-rich-parser/README.md | 245 +++++ microcms-rich-parser/dist/index.d.ts | 18 + microcms-rich-parser/dist/index.d.ts.map | 1 + microcms-rich-parser/dist/index.js | 182 ++++ microcms-rich-parser/dist/index.js.map | 1 + microcms-rich-parser/example.html | 80 ++ microcms-rich-parser/package-lock.json | 889 +++++++++++++++++++ microcms-rich-parser/package.json | 24 + microcms-rich-parser/src/index.ts | 198 +++++ microcms-rich-parser/tsconfig.json | 18 + 12 files changed, 1681 insertions(+) create mode 100644 design/microcms-rich-editor-modern-parser.md create mode 100644 microcms-rich-parser/.npmignore create mode 100644 microcms-rich-parser/README.md create mode 100644 microcms-rich-parser/dist/index.d.ts create mode 100644 microcms-rich-parser/dist/index.d.ts.map create mode 100644 microcms-rich-parser/dist/index.js create mode 100644 microcms-rich-parser/dist/index.js.map create mode 100644 microcms-rich-parser/example.html create mode 100644 microcms-rich-parser/package-lock.json create mode 100644 microcms-rich-parser/package.json create mode 100644 microcms-rich-parser/src/index.ts create mode 100644 microcms-rich-parser/tsconfig.json diff --git a/design/microcms-rich-editor-modern-parser.md b/design/microcms-rich-editor-modern-parser.md new file mode 100644 index 0000000..14f9a36 --- /dev/null +++ b/design/microcms-rich-editor-modern-parser.md @@ -0,0 +1,17 @@ +# MicroCMS で返却される HTML 形式のレスポンスを現代風のブログの見た目になるようにレイアウトを編集するライブラリの作成 + +## 作業概要 + +- microcms で返却される HTML 形式のリッチエディタのレスポンスをパースするライブラリを作成する。 +- ライブラリ名は microcms-rich-parser とする。 +- デザインはダークモードでも見やすいようにする。 +- npm でインストールして組み込めるようにする(local でも可能) +- npm でのインストール方法をドキュメントにまとめる。 + + +## 参考資料 + +レスポンスで返される HTML は以下。 + +```html +

Twitter にかくと炎上しそうなネタでもあるので、割と時流のホットなコンテンツは最近 Bluesky に自分の意見やスタンスを書いていることが多い。

タイトルの通り WFH か RTO かという話はコロナ禍から時間が経って、欧米圏では一定の解答が出つつあり、国内でもある程度企業ごとの方針は固まってきていると思っていたけど、そういった先行してスタンスを取る企業に遅れて最近になってスタンスを変更する企業の話もまたポツポツ聞くようになってきた。

身近でもそういった話を聞いたので Bluesky にこういった一連の投稿をしてみた。

RTO 云々はだいぶ落ち着いたと思ってたけどまだポツポツ話は聞くな。自分はもうRTOになって久しいし、出社も悪くないと思ってるし、なにより出社にこだわらない方がキャリアの選択肢広がってポジティブな側面もあるので、世間の RTOの風潮に対して思うところはないんだけど、まぁRTO かかった時に現場レベルであれこれ画策するのはまぁ無駄かなとは思う。RTO は会社のスタンスの表明であり、選択できるのは乗るか反るかの二択。 また、現場と経営では話してるプロトコルやそもそも見てるところが異なるので現場の意見を組むみたいなことはまずない。 なので納得いかなければ辞める他ない、という類のものなんだよね。

[emahiro (@emahiro.bsky.social)](https://bsky.app/profile/emahiro.bsky.social/post/3l4bungcwtr2e)

僕自身は現職が WFH -> RTO に移行して1年以上経過した上で、出社も悪くはないなと思っている。やはりオフラインの持つ圧倒的なレイテンシの低さはオンラインでは代替できない。この「生身」感こそがプロダクト開発にいい影響があるということを否定することは今の自分にはできない。

一方で仕事においては上記のようなスタンスでいるが、プライベートに目を向けると自分の私生活において今最も大きなイシューである「育児」とRTOが食い合わせが悪いことも重々承知している。

育児とRTOの相性の悪さもよく目にするし自分も当事者なので、わかると思うところも多いが、だからと言ってスタンスがブレることは多分ないので、音楽性の合うところに身を移す方が正直賢明だと思う。 あと思うに WFH にプライベートな生活をフリーライドさせるのは個人的にもどうかな?とは思うようになってきたので、やはり働けないと思うなら辞めるしかないと思う(繰り返し)

[emahiro (@emahiro.bsky.social)](https://bsky.app/profile/emahiro.bsky.social/post/3l4bvhn4peu2u)

正直 WFH 派にも言い分はあるしそれは間違っておらず、一方で RTO にする理由もまぁわからなくもない、という感じを受けている。実際 RTO するまで RTO なんかありえんと思っていた側でもあったものの、やってみると便益も一定ある(その便益を享受するために何処かに負荷が偏っているのでそのケアは欠かせないが)


ちょうどタイムリーに Amazon が RTO を週5にするというニュースが界隈をだいぶ賑やかにさせた。

[Update from Amazon CEO Andy Jassy on return-to-office plans and manager team ratio](https://www.aboutamazon.com/news/company-news/ceo-andy-jassy-latest-update-on-amazon-return-to-office-manager-team-ratio)

これについてはこんなコメントをした。

文化の維持という側面はあるにせよ、コロナ禍の雇い過ぎからのゆり戻しをまだ続けてる、というふうに見えないこともない。

[emahiro (@emahiro.bsky.social)](https://bsky.app/profile/emahiro.bsky.social/post/3l4ehumw2xv2a)

欧米、特に北米のテック企業はコロナ特需で肥大化した従業員の削減をここ数年徹底して進めている。一時期 GAFA のレイオフの話題が国内でもあったが、GAFA はじめとした北米の大企業は未だにこのレイオフもしくは Work Force Adjustment を継続している。以下のようなタレコミもあったけど Amazon のこの動きはブログに書いてあるようなナラティブもあるのだろうけど、個人的には従業員の整理をしている印象が強い。

タレコミ投稿は以下。

<https://x.com/johncodezzz/status/1836205682539786345?s=46&t=6t3beFenTzsAglgkZj3OAg>

当たり前だが数万人という従業金を有する大企業が RTO すれば街に賑わいが戻るし、地方自治体も潤う。コロナ禍でほぼ WFH になったらサンフランシスコのベイエリアが荒廃したなんてニュースを見たことがあったけど、それがシアトルにも当てはまっていた、ということなんだろう。

僕個人としては RTO にするうえで出てくる「組織全体の生産性の向上」「人と交わることで生まれるクリエイティビティ」「組織文化の維持・強化」といった側面よりもこういう現実的な話をちゃんと伝えてもらったほうがいいように思う(この話を Amazon は公表していないが、状況証拠を並べると信憑性は十分に有り得る話なんじゃないかと思っている)


話は少し逸れてしまったが、1個人として見ると WFH ほど良いものはないが、それは個人最適の話であって全体最適で見るとまた話は違ってくるのだろうと思う。

個人最適が全体最適にならないのは常なので、もし全体最適的な意思決定におて個人最適が脅かされ、それが嫌だというのなら、その環境を変えようとするより、自分自身の居場所を変えたほうがいいように思う。

特にプライベートにおける全体最適に対する負荷の閾値は個々人、家庭ごとに異なってくる。我が家の場合はたまたまちょっとだけ高いだけだと思っているし、プライベートを犠牲にしてまで仕事したいか、という一人ひとりの人生観にも関わってくるところでもあるので、自分を大切に生きるために最善を選択するべき。

それがたまたま「反る」ことになってもそれは仕方のない話だと割り切る方が良いように思う。

WFH/RTO の二元論については自分はそういう考えを持っている。

``` diff --git a/microcms-rich-parser/.npmignore b/microcms-rich-parser/.npmignore new file mode 100644 index 0000000..4579bc7 --- /dev/null +++ b/microcms-rich-parser/.npmignore @@ -0,0 +1,8 @@ +src/ +tsconfig.json +*.tsbuildinfo +node_modules/ +.git/ +.gitignore +README.md +examples/ \ No newline at end of file diff --git a/microcms-rich-parser/README.md b/microcms-rich-parser/README.md new file mode 100644 index 0000000..b6af12d --- /dev/null +++ b/microcms-rich-parser/README.md @@ -0,0 +1,245 @@ +# MicroCMS Rich Parser + +A TypeScript library to parse MicroCMS rich editor HTML responses into modern, styled blog layouts with dark mode support. + +## Features + +- 🎨 Modern blog-style layout with professional typography +- 🌙 Dark mode support +- 📱 Responsive design +- 🔗 Enhanced link styling with hover effects +- 💬 Styled blockquotes with visual indicators +- ✨ Clean horizontal dividers +- 🎯 TypeScript support + +## Installation + +### NPM + +```bash +npm install microcms-rich-parser +``` + +### Local Installation + +```bash +# Clone or download the library +cd path/to/microcms-rich-parser +npm install +npm run build + +# In your project +npm install path/to/microcms-rich-parser +``` + +## Usage + +### Basic Usage + +```typescript +import { parseMicroCMSHTML } from 'microcms-rich-parser'; + +const htmlContent = ` +

Twitter にかくと炎上しそうなネタでもあるので、割と時流のホットなコンテンツは最近 Bluesky に自分の意見やスタンスを書いていることが多い。

+

RTO 云々はだいぶ落ち着いたと思ってたけどまだポツポツ話は聞くな。

+
+

話は少し逸れてしまったが、1個人として見ると WFH ほど良いものはないが、それは個人最適の話であって全体最適で見るとまた話は違ってくるのだろうと思う。

+`; + +const styledHTML = parseMicroCMSHTML(htmlContent); +document.getElementById('content').innerHTML = styledHTML; +``` + +### With Dark Mode + +```typescript +import { parseMicroCMSHTML } from 'microcms-rich-parser'; + +const styledHTML = parseMicroCMSHTML(htmlContent, { + darkMode: true +}); +``` + +### Using the Class + +```typescript +import { MicroCMSRichParser } from 'microcms-rich-parser'; + +const parser = new MicroCMSRichParser({ + darkMode: true, + className: 'my-custom-content' +}); + +const styledHTML = parser.parse(htmlContent); +``` + +## API + +### `parseMicroCMSHTML(htmlContent, options?)` + +Convenience function to quickly parse HTML content. + +- `htmlContent` (string): The HTML content from MicroCMS rich editor +- `options` (ParseOptions, optional): Configuration options + +### `MicroCMSRichParser` + +Main parser class for more control. + +#### Constructor Options + +```typescript +interface ParseOptions { + darkMode?: boolean; // Enable dark mode styling (default: false) + className?: string; // CSS class name for wrapper (default: 'microcms-rich-content') +} +``` + +#### Methods + +- `parse(htmlContent: string): string` - Parse HTML and return styled HTML + +## Styling + +The library includes built-in CSS that provides: + +- **Typography**: Clean, readable font stack with proper line height +- **Paragraphs**: Optimized spacing and font sizing +- **Blockquotes**: Styled with left border, background, and quote marks +- **Links**: Enhanced with hover effects and proper contrast +- **Horizontal Rules**: Gradient-based dividers +- **Dark Mode**: Comprehensive dark theme support +- **Responsive**: Mobile-optimized layout + +### Custom Styling + +You can override the default styles by targeting the generated CSS classes: + +```css +.microcms-rich-content { + /* Your custom styles */ +} + +.microcms-rich-content.dark-mode { + /* Your custom dark mode styles */ +} +``` + +## Browser Support + +- Modern browsers with ES2020 support +- Node.js environments with jsdom + +## Development + +```bash +# Install dependencies +npm install + +# Build +npm run build + +# Development mode +npm run dev +``` + +## Publishing to NPM + +### 1. Prepare for Publishing + +```bash +# Build the project +npm run build + +# Test the build +npm pack --dry-run +``` + +### 2. Set NPM Registry and Login + +```bash +# Set registry to npmjs.com (if not already set) +npm config set registry https://registry.npmjs.org/ + +# Login to your NPM account +npm login +``` + +### 3. Update Package Information + +Edit `package.json` to include your information: + +```json +{ + "name": "microcms-rich-parser", + "author": "Your Name ", + "repository": { + "type": "git", + "url": "https://github.com/yourusername/microcms-rich-parser.git" + }, + "homepage": "https://github.com/yourusername/microcms-rich-parser#readme", + "bugs": { + "url": "https://github.com/yourusername/microcms-rich-parser/issues" + } +} +``` + +### 4. Version Management + +```bash +# For patch version (1.0.1) +npm version patch + +# For minor version (1.1.0) +npm version minor + +# For major version (2.0.0) +npm version major +``` + +### 5. Publish to NPM + +```bash +# Publish the package +npm publish + +# For scoped packages (optional) +npm publish --access public +``` + +### 6. Verify Publication + +```bash +# Check if package is available +npm view microcms-rich-parser + +# Install and test in another project +npm install microcms-rich-parser +``` + +### 7. Update Package + +When making updates: + +```bash +# Make your changes +# Build the project +npm run build + +# Update version +npm version patch # or minor/major + +# Publish update +npm publish +``` + +### Notes + +- Ensure your package name is unique on NPM +- Add a `.npmignore` file to exclude unnecessary files +- Test your package locally before publishing +- Consider using `npm pack` to preview what will be published + +## License + +MIT \ No newline at end of file diff --git a/microcms-rich-parser/dist/index.d.ts b/microcms-rich-parser/dist/index.d.ts new file mode 100644 index 0000000..a1461d6 --- /dev/null +++ b/microcms-rich-parser/dist/index.d.ts @@ -0,0 +1,18 @@ +export interface ParseOptions { + darkMode?: boolean; + className?: string; +} +export declare class MicroCMSRichParser { + private options; + constructor(options?: ParseOptions); + parse(htmlContent: string): string; + private processElement; + private processParagraph; + private processBlockquote; + private processHorizontalRule; + private processLink; + private generateCSS; +} +export declare function parseMicroCMSHTML(htmlContent: string, options?: ParseOptions): string; +export default MicroCMSRichParser; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/microcms-rich-parser/dist/index.d.ts.map b/microcms-rich-parser/dist/index.d.ts.map new file mode 100644 index 0000000..c2fb855 --- /dev/null +++ b/microcms-rich-parser/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,OAAO,CAAe;gBAElB,OAAO,GAAE,YAAiB;IAQtC,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAuBlC,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,WAAW;CAqGnB;AAGD,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,CAGrF;AAED,eAAe,kBAAkB,CAAC"} \ No newline at end of file diff --git a/microcms-rich-parser/dist/index.js b/microcms-rich-parser/dist/index.js new file mode 100644 index 0000000..58ba5e8 --- /dev/null +++ b/microcms-rich-parser/dist/index.js @@ -0,0 +1,182 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.MicroCMSRichParser = void 0; +exports.parseMicroCMSHTML = parseMicroCMSHTML; +const jsdom_1 = require("jsdom"); +class MicroCMSRichParser { + constructor(options = {}) { + this.options = { + darkMode: false, + className: 'microcms-rich-content', + ...options + }; + } + parse(htmlContent) { + const dom = new jsdom_1.JSDOM(htmlContent); + const document = dom.window.document; + const body = document.body; + // Create wrapper container + const wrapper = document.createElement('div'); + wrapper.className = `${this.options.className} ${this.options.darkMode ? 'dark-mode' : ''}`; + // Process each element + Array.from(body.children).forEach(element => { + const processedElement = this.processElement(element, document); + wrapper.appendChild(processedElement); + }); + // Add styles + const style = document.createElement('style'); + style.textContent = this.generateCSS(); + wrapper.appendChild(style); + return wrapper.outerHTML; + } + processElement(element, document) { + const tagName = element.tagName.toLowerCase(); + switch (tagName) { + case 'p': + return this.processParagraph(element, document); + case 'blockquote': + return this.processBlockquote(element, document); + case 'hr': + return this.processHorizontalRule(element, document); + case 'a': + return this.processLink(element, document); + default: + return element.cloneNode(true); + } + } + processParagraph(element, document) { + const p = document.createElement('p'); + p.className = 'rich-paragraph'; + p.innerHTML = element.innerHTML; + return p; + } + processBlockquote(element, document) { + const blockquote = document.createElement('blockquote'); + blockquote.className = 'rich-blockquote'; + blockquote.innerHTML = element.innerHTML; + return blockquote; + } + processHorizontalRule(element, document) { + const hr = document.createElement('hr'); + hr.className = 'rich-divider'; + return hr; + } + processLink(element, document) { + const a = document.createElement('a'); + a.className = 'rich-link'; + a.href = element.href; + a.textContent = element.textContent; + a.target = '_blank'; + a.rel = 'noopener noreferrer'; + return a; + } + generateCSS() { + return ` + .microcms-rich-content { + max-width: 800px; + margin: 0 auto; + line-height: 1.7; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + color: #333; + background-color: #fff; + padding: 2rem; + } + + .microcms-rich-content.dark-mode { + color: #e4e4e7; + background-color: #1a1a1a; + } + + .rich-paragraph { + margin-bottom: 1.5rem; + font-size: 1.1rem; + color: inherit; + } + + .rich-blockquote { + margin: 2rem 0; + padding: 1.5rem 2rem; + border-left: 4px solid #3b82f6; + background-color: #f8fafc; + border-radius: 0 8px 8px 0; + font-style: italic; + position: relative; + } + + .dark-mode .rich-blockquote { + background-color: #2d2d30; + border-left-color: #60a5fa; + } + + .rich-blockquote::before { + content: '"'; + font-size: 4rem; + color: #3b82f6; + position: absolute; + top: -10px; + left: 10px; + font-family: serif; + } + + .dark-mode .rich-blockquote::before { + color: #60a5fa; + } + + .rich-divider { + margin: 3rem 0; + border: none; + height: 2px; + background: linear-gradient(to right, transparent, #d1d5db, transparent); + } + + .dark-mode .rich-divider { + background: linear-gradient(to right, transparent, #4b5563, transparent); + } + + .rich-link { + color: #3b82f6; + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: 2px; + transition: all 0.2s ease; + } + + .rich-link:hover { + color: #1d4ed8; + text-decoration-thickness: 3px; + } + + .dark-mode .rich-link { + color: #60a5fa; + } + + .dark-mode .rich-link:hover { + color: #93c5fd; + } + + @media (max-width: 768px) { + .microcms-rich-content { + padding: 1rem; + font-size: 0.95rem; + } + + .rich-paragraph { + font-size: 1rem; + } + + .rich-blockquote { + padding: 1rem; + margin: 1.5rem 0; + } + } + `; + } +} +exports.MicroCMSRichParser = MicroCMSRichParser; +// Convenience function for quick usage +function parseMicroCMSHTML(htmlContent, options) { + const parser = new MicroCMSRichParser(options); + return parser.parse(htmlContent); +} +exports.default = MicroCMSRichParser; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/microcms-rich-parser/dist/index.js.map b/microcms-rich-parser/dist/index.js.map new file mode 100644 index 0000000..a509fdf --- /dev/null +++ b/microcms-rich-parser/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/microcms-rich-parser/example.html b/microcms-rich-parser/example.html new file mode 100644 index 0000000..8d1b427 --- /dev/null +++ b/microcms-rich-parser/example.html @@ -0,0 +1,80 @@ + + + + + + MicroCMS Rich Parser Example + + + +
+

MicroCMS Rich Parser Example

+ +
+
+ +
+
+ +
+
+
+
+ + + + + \ No newline at end of file diff --git a/microcms-rich-parser/package-lock.json b/microcms-rich-parser/package-lock.json new file mode 100644 index 0000000..5b80cfa --- /dev/null +++ b/microcms-rich-parser/package-lock.json @@ -0,0 +1,889 @@ +{ + "name": "microcms-rich-parser", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "microcms-rich-parser", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "jsdom": "^23.0.0" + }, + "devDependencies": { + "@types/jsdom": "^21.0.0", + "@types/node": "^20.0.0", + "typescript": "^5.0.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-2.0.2.tgz", + "integrity": "sha512-x1KXOatwofR6ZAYzXRBL5wrdV0vwNxlTCK9NCuLqAzQYARqGcvFwiJA6A1ERuh+dgeA4Dxm3JBYictIes+SqUQ==", + "license": "MIT", + "dependencies": { + "bidi-js": "^1.0.3", + "css-tree": "^2.3.1", + "is-potential-custom-element-name": "^1.0.1" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", + "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/jsdom": { + "version": "21.1.7", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", + "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/node": { + "version": "20.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz", + "integrity": "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssstyle": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.5.0.tgz", + "integrity": "sha512-/7gw8TGrvH/0g564EnhgFZogTMVe+lifpB7LWU+PEsiq5o83TUXR3fDbzTRXOJhoJwck5IS9ez3Em5LNMMO2aw==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cssstyle/node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/form-data": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "23.2.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.2.0.tgz", + "integrity": "sha512-L88oL7D/8ufIES+Zjz7v0aes+oBMh2Xnh3ygWvL0OaICOomKEPKuPnIfBJekiXr+BHbbMjrWn/xqrDQuxFTeyA==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/dom-selector": "^2.0.1", + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.3", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.16.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + } + } +} diff --git a/microcms-rich-parser/package.json b/microcms-rich-parser/package.json new file mode 100644 index 0000000..85ce609 --- /dev/null +++ b/microcms-rich-parser/package.json @@ -0,0 +1,24 @@ +{ + "name": "microcms-rich-parser", + "version": "1.0.0", + "description": "A library to parse MicroCMS rich editor HTML response into modern blog layout", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "prepare": "npm run build" + }, + "keywords": ["microcms", "rich-editor", "html-parser", "blog", "markdown"], + "author": "", + "license": "MIT", + "devDependencies": { + "typescript": "^5.0.0", + "@types/node": "^20.0.0", + "@types/jsdom": "^21.0.0" + }, + "dependencies": { + "jsdom": "^23.0.0" + }, + "files": ["dist"] +} \ No newline at end of file diff --git a/microcms-rich-parser/src/index.ts b/microcms-rich-parser/src/index.ts new file mode 100644 index 0000000..679977e --- /dev/null +++ b/microcms-rich-parser/src/index.ts @@ -0,0 +1,198 @@ +import { JSDOM } from 'jsdom'; + +export interface ParseOptions { + darkMode?: boolean; + className?: string; +} + +export class MicroCMSRichParser { + private options: ParseOptions; + + constructor(options: ParseOptions = {}) { + this.options = { + darkMode: false, + className: 'microcms-rich-content', + ...options + }; + } + + parse(htmlContent: string): string { + const dom = new JSDOM(htmlContent); + const document = dom.window.document; + const body = document.body; + + // Create wrapper container + const wrapper = document.createElement('div'); + wrapper.className = `${this.options.className} ${this.options.darkMode ? 'dark-mode' : ''}`; + + // Process each element + Array.from(body.children).forEach(element => { + const processedElement = this.processElement(element as Element, document); + wrapper.appendChild(processedElement); + }); + + // Add styles + const style = document.createElement('style'); + style.textContent = this.generateCSS(); + wrapper.appendChild(style); + + return wrapper.outerHTML; + } + + private processElement(element: Element, document: Document): Element { + const tagName = element.tagName.toLowerCase(); + + switch (tagName) { + case 'p': + return this.processParagraph(element, document); + case 'blockquote': + return this.processBlockquote(element, document); + case 'hr': + return this.processHorizontalRule(element, document); + case 'a': + return this.processLink(element, document); + default: + return element.cloneNode(true) as Element; + } + } + + private processParagraph(element: Element, document: Document): Element { + const p = document.createElement('p'); + p.className = 'rich-paragraph'; + p.innerHTML = element.innerHTML; + return p; + } + + private processBlockquote(element: Element, document: Document): Element { + const blockquote = document.createElement('blockquote'); + blockquote.className = 'rich-blockquote'; + blockquote.innerHTML = element.innerHTML; + return blockquote; + } + + private processHorizontalRule(element: Element, document: Document): Element { + const hr = document.createElement('hr'); + hr.className = 'rich-divider'; + return hr; + } + + private processLink(element: Element, document: Document): Element { + const a = document.createElement('a'); + a.className = 'rich-link'; + a.href = (element as HTMLAnchorElement).href; + a.textContent = element.textContent; + a.target = '_blank'; + a.rel = 'noopener noreferrer'; + return a; + } + + private generateCSS(): string { + return ` + .microcms-rich-content { + max-width: 800px; + margin: 0 auto; + line-height: 1.7; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + color: #333; + background-color: #fff; + padding: 2rem; + } + + .microcms-rich-content.dark-mode { + color: #e4e4e7; + background-color: #1a1a1a; + } + + .rich-paragraph { + margin-bottom: 1.5rem; + font-size: 1.1rem; + color: inherit; + } + + .rich-blockquote { + margin: 2rem 0; + padding: 1.5rem 2rem; + border-left: 4px solid #3b82f6; + background-color: #f8fafc; + border-radius: 0 8px 8px 0; + font-style: italic; + position: relative; + } + + .dark-mode .rich-blockquote { + background-color: #2d2d30; + border-left-color: #60a5fa; + } + + .rich-blockquote::before { + content: '"'; + font-size: 4rem; + color: #3b82f6; + position: absolute; + top: -10px; + left: 10px; + font-family: serif; + } + + .dark-mode .rich-blockquote::before { + color: #60a5fa; + } + + .rich-divider { + margin: 3rem 0; + border: none; + height: 2px; + background: linear-gradient(to right, transparent, #d1d5db, transparent); + } + + .dark-mode .rich-divider { + background: linear-gradient(to right, transparent, #4b5563, transparent); + } + + .rich-link { + color: #3b82f6; + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: 2px; + transition: all 0.2s ease; + } + + .rich-link:hover { + color: #1d4ed8; + text-decoration-thickness: 3px; + } + + .dark-mode .rich-link { + color: #60a5fa; + } + + .dark-mode .rich-link:hover { + color: #93c5fd; + } + + @media (max-width: 768px) { + .microcms-rich-content { + padding: 1rem; + font-size: 0.95rem; + } + + .rich-paragraph { + font-size: 1rem; + } + + .rich-blockquote { + padding: 1rem; + margin: 1.5rem 0; + } + } + `; + } +} + +// Convenience function for quick usage +export function parseMicroCMSHTML(htmlContent: string, options?: ParseOptions): string { + const parser = new MicroCMSRichParser(options); + return parser.parse(htmlContent); +} + +export default MicroCMSRichParser; \ No newline at end of file diff --git a/microcms-rich-parser/tsconfig.json b/microcms-rich-parser/tsconfig.json new file mode 100644 index 0000000..3c1d4d9 --- /dev/null +++ b/microcms-rich-parser/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020", "DOM"], + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} \ No newline at end of file