@osmn-byhn/css-formatter-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/package.json +46 -0
- package/src/cli.js +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Osman Beyhan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# CSS Formatter CLI
|
|
2
|
+
|
|
3
|
+
> **A powerful CLI for bidirectional CSS-HTML conversion, powered by [@osmn-byhn/css-formatter](https://www.npmjs.com/package/@osmn-byhn/css-formatter).**
|
|
4
|
+
|
|
5
|
+
This tool allows you to convert between external/internal CSS and inline styles effortlessly directly from your terminal. It's perfect for email templates, production optimization, and modernizing legacy HTML.
|
|
6
|
+
|
|
7
|
+
## 🚀 Key Features
|
|
8
|
+
|
|
9
|
+
- **Bidirectional Conversion**: Move styles from `<style>` tags to inline attributes and back.
|
|
10
|
+
- **Smart Selector Generation**: Automatically generates clean, semantic CSS selectors based on existing classes and structure.
|
|
11
|
+
- **Preserves Critical CSS**: Keeps `@media` queries, `:hover` states, and `@font-face` rules in a `<style>` tag while inlining the rest.
|
|
12
|
+
- **Style Deduplication**: Groups identical inline styles under single CSS rules to keep your output clean.
|
|
13
|
+
|
|
14
|
+
## 📦 Installation
|
|
15
|
+
|
|
16
|
+
You can install it globally via npm:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @osmn-byhn/css-formatter-cli
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or run it instantly using npx:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx css-formatter <command> [options]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 🎯 Usage & Commands
|
|
29
|
+
|
|
30
|
+
### 1. Inlining CSS (`inline`)
|
|
31
|
+
Converts all CSS from `<style>` tags and linked stylesheets into inline `style` attributes.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
css-formatter inline input.html -o output.html
|
|
35
|
+
```
|
|
36
|
+
- **Use Case**: Preparing HTML for email clients that only support inline styles.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
### 2. Extracting to Internal CSS (`internal`)
|
|
41
|
+
Extracts all inline `style` attributes and moves them into a single `<style>` tag in the `<head>`.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
css-formatter internal input.html -o output.html
|
|
45
|
+
```
|
|
46
|
+
- **Use Case**: Refactoring messy inline styles into a readable, centralized format.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### 3. Extracting to External CSS (`extract`)
|
|
51
|
+
Extracts inline styles into a separate `.css` file and adds a `<link>` tag to the HTML.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
css-formatter extract input.html styles.css -o output.html
|
|
55
|
+
```
|
|
56
|
+
- **Use Case**: Optimizing production websites for browser caching by separating CSS from HTML.
|
|
57
|
+
|
|
58
|
+
## 🔧 Options
|
|
59
|
+
|
|
60
|
+
| Argument | Description |
|
|
61
|
+
| :--- | :--- |
|
|
62
|
+
| `<input>` | Path to your input HTML file. |
|
|
63
|
+
| `[cssOutput]` | (Extract only) Name of the generated CSS file. |
|
|
64
|
+
| `-o, --output` | Custom path for the output HTML (defaults to overwriting input). |
|
|
65
|
+
| `-v, --version` | Display version information. |
|
|
66
|
+
| `-h, --help` | Display help for commands. |
|
|
67
|
+
|
|
68
|
+
## 📄 License
|
|
69
|
+
|
|
70
|
+
MIT © Osman Beyhan
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@osmn-byhn/css-formatter-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Command line interface for @osmn-byhn/css-formatter to inline or extract CSS from HTML",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"css-formatter": "src/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"css",
|
|
16
|
+
"formatter",
|
|
17
|
+
"cli",
|
|
18
|
+
"inline",
|
|
19
|
+
"extract",
|
|
20
|
+
"html",
|
|
21
|
+
"email-templates",
|
|
22
|
+
"web-performance"
|
|
23
|
+
],
|
|
24
|
+
"author": "Osman Beyhan",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/osmn-byhn/css-formatter-cli.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/osmn-byhn/css-formatter-cli/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://css-formatter-cli.osmanbeyhan.com",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@osmn-byhn/css-formatter": "^1.0.1",
|
|
39
|
+
"chalk": "^5.6.2",
|
|
40
|
+
"commander": "^14.0.3"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
44
|
+
"release": "pnpm publish --access public --no-git-checks"
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import fs from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { inlineCSS, reverseCSSInternal, reverseCSSExternal } from '@osmn-byhn/css-formatter';
|
|
8
|
+
|
|
9
|
+
const program = new Command();
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('css-formatter')
|
|
13
|
+
.description('CLI tool for inlining and extracting CSS using @osmn-byhn/css-formatter')
|
|
14
|
+
.version('1.0.0');
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.command('inline')
|
|
18
|
+
.description('Inlines CSS into the HTML file')
|
|
19
|
+
.argument('<input>', 'Input HTML file path')
|
|
20
|
+
.option('-o, --output <path>', 'Output file path (defaults to overwriting input)')
|
|
21
|
+
.action(async (input, options) => {
|
|
22
|
+
try {
|
|
23
|
+
const inputPath = path.resolve(input);
|
|
24
|
+
const html = await fs.readFile(inputPath, 'utf-8');
|
|
25
|
+
|
|
26
|
+
console.log(chalk.blue(`🚀 Inlining CSS in ${input}...`));
|
|
27
|
+
const result = await inlineCSS(html);
|
|
28
|
+
|
|
29
|
+
const outputPath = options.output ? path.resolve(options.output) : inputPath;
|
|
30
|
+
await fs.writeFile(outputPath, result);
|
|
31
|
+
|
|
32
|
+
console.log(chalk.green(`✅ Successfully inlined CSS. Saved to: ${outputPath}`));
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(chalk.red(`❌ Error: ${error.message}`));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
program
|
|
40
|
+
.command('internal')
|
|
41
|
+
.description('Extracts inline styles into a <style> tag')
|
|
42
|
+
.argument('<input>', 'Input HTML file path')
|
|
43
|
+
.option('-o, --output <path>', 'Output file path (defaults to overwriting input)')
|
|
44
|
+
.action(async (input, options) => {
|
|
45
|
+
try {
|
|
46
|
+
const inputPath = path.resolve(input);
|
|
47
|
+
const html = await fs.readFile(inputPath, 'utf-8');
|
|
48
|
+
|
|
49
|
+
console.log(chalk.blue(`🚀 Extracting inline styles to internal <style> tag in ${input}...`));
|
|
50
|
+
const result = await reverseCSSInternal(html);
|
|
51
|
+
|
|
52
|
+
const outputPath = options.output ? path.resolve(options.output) : inputPath;
|
|
53
|
+
await fs.writeFile(outputPath, result);
|
|
54
|
+
|
|
55
|
+
console.log(chalk.green(`✅ Successfully extracted styles to internal <style>. Saved to: ${outputPath}`));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(chalk.red(`❌ Error: ${error.message}`));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
program
|
|
63
|
+
.command('extract')
|
|
64
|
+
.description('Extracts inline styles into an external CSS file')
|
|
65
|
+
.argument('<input>', 'Input HTML file path')
|
|
66
|
+
.argument('[cssOutput]', 'Output CSS file path (defaults to styles.css)')
|
|
67
|
+
.option('-o, --output <path>', 'Output HTML file path (defaults to overwriting input)')
|
|
68
|
+
.action(async (input, cssOutput, options) => {
|
|
69
|
+
try {
|
|
70
|
+
const inputPath = path.resolve(input);
|
|
71
|
+
const html = await fs.readFile(inputPath, 'utf-8');
|
|
72
|
+
|
|
73
|
+
const cssFileName = cssOutput || 'styles.css';
|
|
74
|
+
const cssPath = path.resolve(path.dirname(inputPath), cssFileName);
|
|
75
|
+
|
|
76
|
+
console.log(chalk.blue(`🚀 Extracting inline styles from ${input} to ${cssFileName}...`));
|
|
77
|
+
const { html: htmlOutput, css: cssResult } = await reverseCSSExternal(html);
|
|
78
|
+
|
|
79
|
+
// The library's reverseCSSExternal might be putting a default link tag.
|
|
80
|
+
// We should check if we need to adjust the link tag href if the user provided a specific path.
|
|
81
|
+
|
|
82
|
+
const outputPath = options.output ? path.resolve(options.output) : inputPath;
|
|
83
|
+
|
|
84
|
+
await fs.writeFile(outputPath, htmlOutput);
|
|
85
|
+
await fs.writeFile(cssPath, cssResult);
|
|
86
|
+
|
|
87
|
+
console.log(chalk.green(`✅ Successfully extracted styles.`));
|
|
88
|
+
console.log(chalk.green(` HTML saved to: ${outputPath}`));
|
|
89
|
+
console.log(chalk.green(` CSS saved to: ${cssPath}`));
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error(chalk.red(`❌ Error: ${error.message}`));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
program.parse();
|