tailwind-hyperclay 0.1.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/index.js +86 -0
- package/package.json +22 -0
- package/scripts/release.sh +248 -0
- package/test/test.js +34 -0
package/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { compile } from 'tailwindcss';
|
|
2
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
export async function generateCSS({ input, output }) {
|
|
10
|
+
const html = await readFile(input, 'utf-8');
|
|
11
|
+
|
|
12
|
+
const css = await compileTailwind(html);
|
|
13
|
+
|
|
14
|
+
if (output) {
|
|
15
|
+
await writeFile(output, css);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return css;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function compileTailwind(html) {
|
|
22
|
+
const inputCSS = `
|
|
23
|
+
@import "tailwindcss";
|
|
24
|
+
@plugin "@tailwindcss/typography";
|
|
25
|
+
@plugin "@tailwindcss/forms" { strategy: "class"; }
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const compiler = await compile(inputCSS, {
|
|
29
|
+
loadStylesheet: async (id, base) => {
|
|
30
|
+
let resolved;
|
|
31
|
+
const searchPaths = [base || process.cwd()];
|
|
32
|
+
|
|
33
|
+
// Try resolving as-is first (for .css files)
|
|
34
|
+
try {
|
|
35
|
+
resolved = require.resolve(id, { paths: searchPaths });
|
|
36
|
+
} catch {
|
|
37
|
+
// If that fails, try with /index.css suffix (for package imports like "tailwindcss")
|
|
38
|
+
resolved = require.resolve(`${id}/index.css`, { paths: searchPaths });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// If resolved to a JS file, try the CSS variant
|
|
42
|
+
if (resolved.endsWith('.js') || resolved.endsWith('.mjs')) {
|
|
43
|
+
resolved = require.resolve(`${id}/index.css`, { paths: searchPaths });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const content = await readFile(resolved, 'utf-8');
|
|
47
|
+
return { content, base: path.dirname(resolved) };
|
|
48
|
+
},
|
|
49
|
+
loadModule: async (id, base) => {
|
|
50
|
+
const resolved = require.resolve(id, { paths: [base || process.cwd()] });
|
|
51
|
+
const mod = await import(pathToFileURL(resolved).href);
|
|
52
|
+
return { module: mod.default, base: path.dirname(resolved) };
|
|
53
|
+
},
|
|
54
|
+
loadPlugin: async (plugin) => {
|
|
55
|
+
const resolved = require.resolve(plugin);
|
|
56
|
+
const mod = await import(pathToFileURL(resolved).href);
|
|
57
|
+
return mod.default;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const candidates = extractCandidates(html);
|
|
62
|
+
const css = compiler.build(candidates);
|
|
63
|
+
|
|
64
|
+
return css;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function extractCandidates(html) {
|
|
68
|
+
const candidates = new Set();
|
|
69
|
+
|
|
70
|
+
// Extract class attribute values
|
|
71
|
+
const classRegex = /class\s*=\s*["']([^"']+)["']/gi;
|
|
72
|
+
let match;
|
|
73
|
+
while ((match = classRegex.exec(html)) !== null) {
|
|
74
|
+
const classes = match[1].split(/\s+/);
|
|
75
|
+
for (const cls of classes) {
|
|
76
|
+
if (cls) candidates.add(cls);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return Array.from(candidates);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function hasTailwindLink(html, appName) {
|
|
84
|
+
const pattern = new RegExp(`https://hyperclay\\.com/tailwindcss/${appName}\\.css`);
|
|
85
|
+
return pattern.test(html);
|
|
86
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tailwind-hyperclay",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "On-save Tailwind CSS generator for Hyperclay",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "node test/test.js",
|
|
12
|
+
"release": "./scripts/release.sh"
|
|
13
|
+
},
|
|
14
|
+
"keywords": ["tailwind", "hyperclay", "css"],
|
|
15
|
+
"author": "",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"tailwindcss": "^4.0.0-beta.8",
|
|
19
|
+
"@tailwindcss/typography": "^0.5.15",
|
|
20
|
+
"@tailwindcss/forms": "^0.5.9"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e # Exit on error
|
|
3
|
+
|
|
4
|
+
# tailwind-hyperclay Automated Release Script
|
|
5
|
+
|
|
6
|
+
echo "╔════════════════════════════════════════╗"
|
|
7
|
+
echo "║ tailwind-hyperclay Release ║"
|
|
8
|
+
echo "╚════════════════════════════════════════╝"
|
|
9
|
+
echo ""
|
|
10
|
+
|
|
11
|
+
# Color codes
|
|
12
|
+
RED='\033[0;31m'
|
|
13
|
+
GREEN='\033[0;32m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
BLUE='\033[0;34m'
|
|
16
|
+
NC='\033[0m' # No Color
|
|
17
|
+
|
|
18
|
+
# Helper functions
|
|
19
|
+
info() { echo -e "${BLUE}ℹ${NC} $1"; }
|
|
20
|
+
success() { echo -e "${GREEN}✓${NC} $1"; }
|
|
21
|
+
warn() { echo -e "${YELLOW}⚠${NC} $1"; }
|
|
22
|
+
error() { echo -e "${RED}✗${NC} $1"; }
|
|
23
|
+
|
|
24
|
+
# Check if we're in the right directory
|
|
25
|
+
if [ ! -f "package.json" ] || ! grep -q '"name": "tailwind-hyperclay"' package.json; then
|
|
26
|
+
error "Must run from tailwind-hyperclay root directory"
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# ============================================
|
|
31
|
+
# STEP 1: Collect Release Information
|
|
32
|
+
# ============================================
|
|
33
|
+
|
|
34
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
35
|
+
echo "Step 1: Release Information"
|
|
36
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
37
|
+
echo ""
|
|
38
|
+
|
|
39
|
+
# Get version bump type
|
|
40
|
+
echo "Select version bump type:"
|
|
41
|
+
echo " 1) patch (bug fixes, 1.0.0 → 1.0.1)"
|
|
42
|
+
echo " 2) minor (new features, 1.0.0 → 1.1.0)"
|
|
43
|
+
echo " 3) major (breaking changes, 1.0.0 → 2.0.0)"
|
|
44
|
+
echo " 4) custom (enter version manually)"
|
|
45
|
+
echo ""
|
|
46
|
+
read -p "Enter choice [1-4]: " version_choice
|
|
47
|
+
|
|
48
|
+
case $version_choice in
|
|
49
|
+
1) VERSION_TYPE="patch" ;;
|
|
50
|
+
2) VERSION_TYPE="minor" ;;
|
|
51
|
+
3) VERSION_TYPE="major" ;;
|
|
52
|
+
4)
|
|
53
|
+
read -p "Enter custom version (e.g., 2.0.0-beta.1): " CUSTOM_VERSION
|
|
54
|
+
VERSION_TYPE="custom"
|
|
55
|
+
;;
|
|
56
|
+
*)
|
|
57
|
+
error "Invalid choice"
|
|
58
|
+
exit 1
|
|
59
|
+
;;
|
|
60
|
+
esac
|
|
61
|
+
|
|
62
|
+
# Publish tag (latest, beta, alpha)
|
|
63
|
+
echo ""
|
|
64
|
+
read -p "NPM publish tag [latest/beta/alpha] (default: latest): " NPM_TAG
|
|
65
|
+
NPM_TAG=${NPM_TAG:-latest}
|
|
66
|
+
|
|
67
|
+
# ============================================
|
|
68
|
+
# STEP 2: Pre-Release Checks
|
|
69
|
+
# ============================================
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
73
|
+
echo "Step 2: Pre-Release Checks"
|
|
74
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
75
|
+
echo ""
|
|
76
|
+
|
|
77
|
+
# Check git status
|
|
78
|
+
info "Checking git status..."
|
|
79
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
80
|
+
warn "You have uncommitted changes:"
|
|
81
|
+
git status --short
|
|
82
|
+
read -p "Continue anyway? [y/N]: " continue_dirty
|
|
83
|
+
if [[ ! $continue_dirty =~ ^[Yy]$ ]]; then
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
else
|
|
87
|
+
success "Working directory clean"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# ============================================
|
|
91
|
+
# STEP 3: Test
|
|
92
|
+
# ============================================
|
|
93
|
+
|
|
94
|
+
echo ""
|
|
95
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
96
|
+
echo "Step 3: Test"
|
|
97
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
98
|
+
echo ""
|
|
99
|
+
|
|
100
|
+
# Run tests
|
|
101
|
+
info "Running tests..."
|
|
102
|
+
if npm test; then
|
|
103
|
+
success "All tests passed"
|
|
104
|
+
else
|
|
105
|
+
error "Tests failed"
|
|
106
|
+
read -p "Continue anyway? [y/N]: " continue_tests
|
|
107
|
+
if [[ ! $continue_tests =~ ^[Yy]$ ]]; then
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# ============================================
|
|
113
|
+
# STEP 4: Version Bump
|
|
114
|
+
# ============================================
|
|
115
|
+
|
|
116
|
+
echo ""
|
|
117
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
118
|
+
echo "Step 4: Version Bump"
|
|
119
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
120
|
+
echo ""
|
|
121
|
+
|
|
122
|
+
# Get current version
|
|
123
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
124
|
+
info "Current version: $CURRENT_VERSION"
|
|
125
|
+
|
|
126
|
+
# Bump version
|
|
127
|
+
if [ "$VERSION_TYPE" = "custom" ]; then
|
|
128
|
+
NEW_VERSION="$CUSTOM_VERSION"
|
|
129
|
+
npm version "$NEW_VERSION" --no-git-tag-version
|
|
130
|
+
else
|
|
131
|
+
NEW_VERSION=$(npm version "$VERSION_TYPE" --no-git-tag-version | sed 's/^v//')
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
success "Version bumped to: $NEW_VERSION"
|
|
135
|
+
|
|
136
|
+
# ============================================
|
|
137
|
+
# STEP 5: Commit and Tag
|
|
138
|
+
# ============================================
|
|
139
|
+
|
|
140
|
+
echo ""
|
|
141
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
142
|
+
echo "Step 5: Commit and Tag"
|
|
143
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
144
|
+
echo ""
|
|
145
|
+
|
|
146
|
+
# Stage changes
|
|
147
|
+
git add package.json package-lock.json
|
|
148
|
+
|
|
149
|
+
# Commit
|
|
150
|
+
COMMIT_MSG="chore: release v$NEW_VERSION"
|
|
151
|
+
git commit -m "$COMMIT_MSG"
|
|
152
|
+
success "Changes committed"
|
|
153
|
+
|
|
154
|
+
# Create tag
|
|
155
|
+
git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION"
|
|
156
|
+
success "Tag created: v$NEW_VERSION"
|
|
157
|
+
|
|
158
|
+
# ============================================
|
|
159
|
+
# STEP 6: Dry Run
|
|
160
|
+
# ============================================
|
|
161
|
+
|
|
162
|
+
echo ""
|
|
163
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
164
|
+
echo "Step 6: Pre-Publish Verification"
|
|
165
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
166
|
+
echo ""
|
|
167
|
+
|
|
168
|
+
info "Running npm publish --dry-run..."
|
|
169
|
+
npm publish --dry-run --tag "$NPM_TAG"
|
|
170
|
+
|
|
171
|
+
echo ""
|
|
172
|
+
warn "Review the output above carefully!"
|
|
173
|
+
echo ""
|
|
174
|
+
|
|
175
|
+
# ============================================
|
|
176
|
+
# STEP 7: Publish
|
|
177
|
+
# ============================================
|
|
178
|
+
|
|
179
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
180
|
+
echo "Step 7: Publish to npm"
|
|
181
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
182
|
+
echo ""
|
|
183
|
+
|
|
184
|
+
echo "Summary:"
|
|
185
|
+
echo " Version: $CURRENT_VERSION → $NEW_VERSION"
|
|
186
|
+
echo " Tag: $NPM_TAG"
|
|
187
|
+
echo " Git tag: v$NEW_VERSION"
|
|
188
|
+
echo ""
|
|
189
|
+
|
|
190
|
+
read -p "Publish to npm? [y/N]: " confirm_publish
|
|
191
|
+
if [[ ! $confirm_publish =~ ^[Yy]$ ]]; then
|
|
192
|
+
warn "Publish cancelled"
|
|
193
|
+
echo ""
|
|
194
|
+
echo "To manually publish later:"
|
|
195
|
+
echo " git push origin main"
|
|
196
|
+
echo " git push origin --tags"
|
|
197
|
+
echo " npm publish --tag $NPM_TAG"
|
|
198
|
+
exit 0
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# Publish to npm
|
|
202
|
+
info "Publishing to npm..."
|
|
203
|
+
npm publish --tag "$NPM_TAG"
|
|
204
|
+
success "Published to npm!"
|
|
205
|
+
|
|
206
|
+
# Push to git
|
|
207
|
+
info "Pushing to GitHub..."
|
|
208
|
+
git push origin main
|
|
209
|
+
git push origin --tags
|
|
210
|
+
success "Pushed to GitHub"
|
|
211
|
+
|
|
212
|
+
# ============================================
|
|
213
|
+
# STEP 8: Verify
|
|
214
|
+
# ============================================
|
|
215
|
+
|
|
216
|
+
echo ""
|
|
217
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
218
|
+
echo "Step 8: Verification"
|
|
219
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
220
|
+
echo ""
|
|
221
|
+
|
|
222
|
+
sleep 5 # Give npm a moment to update
|
|
223
|
+
|
|
224
|
+
info "Verifying npm publication..."
|
|
225
|
+
NPM_VERSION=$(npm view tailwind-hyperclay version 2>/dev/null || echo "unknown")
|
|
226
|
+
if [ "$NPM_VERSION" = "$NEW_VERSION" ]; then
|
|
227
|
+
success "npm shows version: $NPM_VERSION"
|
|
228
|
+
else
|
|
229
|
+
warn "npm shows version: $NPM_VERSION (expected: $NEW_VERSION)"
|
|
230
|
+
warn "It may take a few moments for npm to update"
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
# ============================================
|
|
234
|
+
# Done!
|
|
235
|
+
# ============================================
|
|
236
|
+
|
|
237
|
+
echo ""
|
|
238
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
239
|
+
success "Release Complete!"
|
|
240
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
241
|
+
echo ""
|
|
242
|
+
echo "Released: tailwind-hyperclay@$NEW_VERSION"
|
|
243
|
+
echo "npm tag: $NPM_TAG"
|
|
244
|
+
echo "Git tag: v$NEW_VERSION"
|
|
245
|
+
echo ""
|
|
246
|
+
echo "Install with:"
|
|
247
|
+
echo " npm install tailwind-hyperclay@$NEW_VERSION"
|
|
248
|
+
echo ""
|
package/test/test.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { compileTailwind, hasTailwindLink } from '../index.js';
|
|
2
|
+
|
|
3
|
+
const testHTML = `
|
|
4
|
+
<!DOCTYPE html>
|
|
5
|
+
<html>
|
|
6
|
+
<head>
|
|
7
|
+
<link href="https://hyperclay.com/tailwindcss/myApp.css" rel="stylesheet">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="prose mx-auto p-4">
|
|
11
|
+
<h1 class="text-2xl font-bold text-blue-600">Hello</h1>
|
|
12
|
+
<input type="text" class="form-input mt-2">
|
|
13
|
+
</div>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
async function runTests() {
|
|
19
|
+
console.log('Testing hasTailwindLink...');
|
|
20
|
+
console.log(' myApp:', hasTailwindLink(testHTML, 'myApp')); // true
|
|
21
|
+
console.log(' other:', hasTailwindLink(testHTML, 'other')); // false
|
|
22
|
+
|
|
23
|
+
console.log('\nTesting compileTailwind...');
|
|
24
|
+
const css = await compileTailwind(testHTML);
|
|
25
|
+
console.log(' Generated CSS length:', css.length);
|
|
26
|
+
console.log(' Contains .prose:', css.includes('.prose'));
|
|
27
|
+
console.log(' Contains .form-input:', css.includes('.form-input'));
|
|
28
|
+
console.log(' Contains .text-2xl:', css.includes('.text-2xl'));
|
|
29
|
+
|
|
30
|
+
console.log('\nSample output (first 500 chars):');
|
|
31
|
+
console.log(css.slice(0, 500));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
runTests().catch(console.error);
|