Skip to content

Commit cafd602

Browse files
committed
Initial commit
1 parent e7e1ace commit cafd602

17 files changed

+5341
-0
lines changed

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
root = true
2+
3+
[*]
4+
indent_size = 2

.github/workflows/ci.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
name: Test
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout repository
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: 'lts/*'
22+
cache: 'npm'
23+
24+
- name: Install dependencies
25+
run: npm ci
26+
27+
- name: Build project
28+
run: npm run build
29+
30+
- name: Run linter
31+
run: npm run lint
32+
33+
- name: Run unit tests
34+
run: npm run test:run

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.DS_Store
2+
CLAUDE.md
3+
coverage/
4+
dist/
5+
node_modules/

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
## [0.1.0] - 2025-08-20
11+
12+
### Added
13+
14+
- Initial release of postcss-inline-extract
15+
- Extract inline styles from HTML `style` attributes
16+
- Support for multiple selector generation strategies:
17+
- `class`: Use existing class attributes (`.className`)
18+
- `id`: Use existing id attributes (`#idName`)
19+
- `hash`: Generate random hash selectors (`.abc123`)
20+
- Optional extraction from `<style>` tags via `styleTags` option
21+
- Automatic property merging for duplicate selectors
22+
- Configurable CSS indentation via `indent` option
23+
- TypeScript support with full type definitions
24+
- Support for compound selectors from multiple classes
25+
- Comprehensive test suite with 43 test cases using Vitest
26+
- PostCSS Plugin Guidelines compliance
27+
- Proper error handling with PostCSS error reporting
28+
29+
### Technical Details
30+
31+
- Built with TypeScript targeting ES2018
32+
- Uses `node-html-parser` for HTML parsing
33+
- PostCSS as peer dependency
34+
- Rollup + esbuild for bundling
35+
- ESLint with strict TypeScript configuration
36+
- Vitest for testing with coverage reporting
37+
- GitHub Actions CI workflow for automated testing
38+
39+
[Unreleased]: https://github.com/KNOWLEDGECODE/postcss-inline-extract/compare/v0.1.0...HEAD
40+
[0.1.0]: https://github.com/KNOWLEDGECODE/postcss-inline-extract/releases/tag/v0.1.0

README.md

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# PostCSS Inline Extract
2+
3+
[<img src="https://postcss.org/logo.svg" alt="PostCSS Logo" width="90" height="90" align="right">][PostCSS]
4+
5+
[![CI](https://github.com/knowledgecode/postcss-inline-extract/actions/workflows/ci.yml/badge.svg)](https://github.com/knowledgecode/postcss-inline-extract/actions/workflows/ci.yml)
6+
[![npm](https://img.shields.io/npm/v/postcss-inline-extract)](https://www.npmjs.com/package/postcss-inline-extract)
7+
8+
[PostCSS] plugin to extract inline styles from HTML and convert them to CSS rules.
9+
10+
This plugin helps you extract `style` attributes from HTML elements and convert them into structured CSS rules with customizable selectors.
11+
12+
```css
13+
/* Input CSS (empty or existing styles) */
14+
15+
/* HTML input with inline styles */
16+
<div style="color: red; margin: 10px;" class="button">Click me</div>
17+
<span style="font-size: 14px;" id="text">Hello</span>
18+
```
19+
20+
```css
21+
/* Output CSS */
22+
.button {
23+
color: red;
24+
margin: 10px;
25+
}
26+
27+
#text {
28+
font-size: 14px;
29+
}
30+
```
31+
32+
## Features
33+
34+
- Extract inline styles from HTML `style` attributes
35+
- Multiple selector generation strategies (class, id, hash)
36+
- Optional extraction from `<style>` tags
37+
- Automatic property merging for duplicate selectors
38+
- TypeScript support with full type definitions
39+
- Fast and lightweight with minimal dependencies
40+
41+
## Installation
42+
43+
```bash
44+
npm install --save-dev postcss postcss-inline-extract
45+
```
46+
47+
## Usage
48+
49+
### Basic Usage
50+
51+
```javascript
52+
const postcss = require('postcss');
53+
const inlineExtract = require('postcss-inline-extract');
54+
55+
const html = `
56+
<div style="color: red; margin: 10px;" class="button">Click me</div>
57+
<span style="font-size: 14px;" class="text">Hello</span>
58+
`;
59+
60+
postcss([
61+
inlineExtract({ html })
62+
])
63+
.process('', { from: undefined })
64+
.then(result => {
65+
console.log(result.css);
66+
/*
67+
.button {
68+
color: red;
69+
margin: 10px;
70+
}
71+
.text {
72+
font-size: 14px;
73+
}
74+
*/
75+
});
76+
```
77+
78+
### With PostCSS Configuration
79+
80+
```javascript
81+
// postcss.config.js
82+
module.exports = {
83+
plugins: [
84+
require('postcss-inline-extract')({
85+
html: require('fs').readFileSync('src/index.html', 'utf8')
86+
})
87+
]
88+
};
89+
```
90+
91+
## Options
92+
93+
### `html` (required)
94+
95+
Type: `string`
96+
97+
The HTML content to extract inline styles from.
98+
99+
```javascript
100+
inlineExtract({
101+
html: '<div style="color: red;" class="button">Click me</div>'
102+
})
103+
```
104+
105+
### `selector`
106+
107+
Type: `'class' | 'id' | 'hash' | Array<'class' | 'id' | 'hash'>`
108+
Default: `'class'`
109+
110+
Strategy for generating CSS selectors:
111+
112+
- `'class'`: Use existing `class` attribute (`.className`). Elements without a `class` attribute will be ignored.
113+
- `'id'`: Use existing `id` attribute (`#idName`). Elements without an `id` attribute will be ignored.
114+
- `'hash'`: Generate random hash selectors (`.abc123`) for all elements with inline styles.
115+
116+
```javascript
117+
// Use class attributes
118+
inlineExtract({
119+
html: htmlContent,
120+
selector: 'class'
121+
})
122+
123+
// Use ID attributes
124+
inlineExtract({
125+
html: htmlContent,
126+
selector: 'id'
127+
})
128+
129+
// Priority order: try class first, then id
130+
inlineExtract({
131+
html: htmlContent,
132+
selector: ['class', 'id']
133+
})
134+
```
135+
136+
### `styleTags`
137+
138+
Type: `boolean`
139+
Default: `false`
140+
141+
Whether to also extract CSS from `<style>` tags in the HTML.
142+
143+
```javascript
144+
inlineExtract({
145+
html: `
146+
<style>
147+
.existing { margin: 20px; }
148+
</style>
149+
<div style="color: red;" class="button">Click me</div>
150+
`,
151+
styleTags: true
152+
})
153+
```
154+
155+
### `indent`
156+
157+
Type: `number`
158+
Default: `2`
159+
160+
Number of spaces for CSS indentation.
161+
162+
```javascript
163+
inlineExtract({
164+
html: htmlContent,
165+
indent: 4
166+
})
167+
```
168+
169+
## Examples
170+
171+
### Multiple Classes (Compound Selectors)
172+
173+
```html
174+
<div style="color: blue; padding: 15px;" class="button primary large">
175+
Submit Button
176+
</div>
177+
```
178+
179+
```css
180+
/* Output: Creates compound selector from multiple classes */
181+
.button.primary.large {
182+
color: blue;
183+
padding: 15px;
184+
}
185+
```
186+
187+
### Multiple Elements with Same Class
188+
189+
```html
190+
<div style="color: red;" class="button">Button 1</div>
191+
<div style="margin: 10px;" class="button">Button 2</div>
192+
```
193+
194+
```css
195+
/* Output: Properties are automatically merged */
196+
.button {
197+
color: red;
198+
margin: 10px;
199+
}
200+
```
201+
202+
### Hash Selector Generation
203+
204+
```html
205+
<div style="color: blue;">No class or ID</div>
206+
```
207+
208+
```javascript
209+
inlineExtract({
210+
html: htmlContent,
211+
selector: 'hash'
212+
})
213+
```
214+
215+
```css
216+
/* Output: Random hash selector */
217+
.a1b2c3 {
218+
color: blue;
219+
}
220+
```
221+
222+
## TypeScript Support
223+
224+
This plugin includes full TypeScript definitions:
225+
226+
```typescript
227+
import postcss from 'postcss';
228+
import inlineExtract, { PluginOptions, SelectorType } from 'postcss-inline-extract';
229+
230+
const options: PluginOptions = {
231+
html: '<div style="color: red;" class="button">Click me</div>',
232+
selector: 'class' as SelectorType,
233+
styleTags: false,
234+
indent: 2
235+
};
236+
237+
const processor = postcss([inlineExtract(options)]);
238+
```
239+
240+
## License
241+
242+
[MIT License](LICENSE)
243+
244+
[PostCSS]: https://github.com/postcss/postcss

0 commit comments

Comments
 (0)