@vv0rkz/js-template 1.8.2 → 1.8.3
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vv0rkz/js-template",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
4
4
|
"description": "Reusable setup for JS projects with husky, changelog, gh tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"@commitlint/cli": "^20.1.0",
|
|
34
34
|
"@commitlint/config-conventional": "^20.0.0",
|
|
35
35
|
"changelogen": "^0.6.2",
|
|
36
|
-
"husky": "^9.1.7"
|
|
36
|
+
"husky": "^9.1.7",
|
|
37
|
+
"sharp": "^0.34.5"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"browser-sync": "^3.0.4"
|
package/templates/jst.config.js
CHANGED
|
@@ -83,14 +83,26 @@ export default {
|
|
|
83
83
|
* Настройки релиза (`jst release`)
|
|
84
84
|
*/
|
|
85
85
|
release: {
|
|
86
|
-
/**
|
|
87
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Настройки демо
|
|
88
|
+
*/
|
|
89
|
+
demo: {
|
|
90
|
+
/** Требовать демо перед релизом (true | false) */
|
|
91
|
+
enable: true,
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
/** Директория для демо-файлов */
|
|
94
|
+
dir: 'docs',
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
|
|
96
|
+
/** Допустимые форматы демо-файлов */
|
|
97
|
+
formats: ['gif', 'png'],
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Способ отображения демо в README
|
|
101
|
+
* 'click' — PNG превью, клик открывает GIF (быстрая загрузка)
|
|
102
|
+
* 'side-by-side' — PNG + GIF рядом (GIF грузится автоматически)
|
|
103
|
+
*/
|
|
104
|
+
style: 'click',
|
|
105
|
+
},
|
|
94
106
|
},
|
|
95
107
|
|
|
96
108
|
/**
|
|
@@ -5,7 +5,7 @@ import { loadConfig } from './config.js'
|
|
|
5
5
|
|
|
6
6
|
const config = await loadConfig()
|
|
7
7
|
|
|
8
|
-
if (!config.release.
|
|
8
|
+
if (!config.release.demo.enable) {
|
|
9
9
|
console.log('⏭️ Проверка демо отключена')
|
|
10
10
|
process.exit(0)
|
|
11
11
|
}
|
|
@@ -24,7 +24,7 @@ if (commitMessages.includes('feat:')) {
|
|
|
24
24
|
|
|
25
25
|
console.log(`📦 Предполагаемая следующая версия: ${nextVersion}`)
|
|
26
26
|
|
|
27
|
-
const { demoDir, demoFormats } = config.release
|
|
27
|
+
const { dir: demoDir, formats: demoFormats } = config.release.demo
|
|
28
28
|
const hasDemo = demoFormats.some((fmt) => existsSync(`${demoDir}/${nextVersion}.${fmt}`))
|
|
29
29
|
|
|
30
30
|
if (!hasDemo) {
|
package/tools-gh/config.js
CHANGED
|
@@ -19,9 +19,12 @@ const DEFAULTS = {
|
|
|
19
19
|
closeKeyword: 'close',
|
|
20
20
|
},
|
|
21
21
|
release: {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
demo: {
|
|
23
|
+
enable: true,
|
|
24
|
+
dir: 'docs',
|
|
25
|
+
formats: ['gif', 'png'],
|
|
26
|
+
style: 'click',
|
|
27
|
+
},
|
|
25
28
|
},
|
|
26
29
|
changelog: {
|
|
27
30
|
types: {
|
package/tools-gh/release.js
CHANGED
|
@@ -22,7 +22,7 @@ if (!currentVersion) {
|
|
|
22
22
|
console.log(`📦 Текущая версия: ${currentVersion}`)
|
|
23
23
|
|
|
24
24
|
// 2. Demo check (configurable)
|
|
25
|
-
if (config.release.
|
|
25
|
+
if (config.release.demo.enable) {
|
|
26
26
|
const [major, minor, patch] = currentVersion.split('.').map(Number)
|
|
27
27
|
const recentCommits = execSync('git log --oneline -10', { encoding: 'utf8' })
|
|
28
28
|
const nextVersion = recentCommits.includes('feat:')
|
|
@@ -31,7 +31,7 @@ if (config.release.requireDemo) {
|
|
|
31
31
|
|
|
32
32
|
console.log(`📦 Предполагаемая следующая версия: ${nextVersion}`)
|
|
33
33
|
|
|
34
|
-
const { demoDir, demoFormats } = config.release
|
|
34
|
+
const { dir: demoDir, formats: demoFormats } = config.release.demo
|
|
35
35
|
const hasDemo = demoFormats.some((fmt) => existsSync(`${demoDir}/${nextVersion}.${fmt}`))
|
|
36
36
|
|
|
37
37
|
if (!hasDemo) {
|
|
@@ -42,7 +42,7 @@ if (config.release.requireDemo) {
|
|
|
42
42
|
|
|
43
43
|
console.log(`✅ Демо для ${nextVersion} готово!`)
|
|
44
44
|
} else {
|
|
45
|
-
console.log('⏭️ Проверка демо отключена (release.
|
|
45
|
+
console.log('⏭️ Проверка демо отключена (release.demo.enable = false)')
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// 3. Warning for 0.x.x
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execSync
|
|
2
|
+
import { execSync } from 'child_process'
|
|
3
3
|
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
4
|
+
import sharp from 'sharp'
|
|
4
5
|
import { loadConfig } from './config.js'
|
|
5
6
|
|
|
6
7
|
const config = await loadConfig()
|
|
7
|
-
const demoDir = config.release.
|
|
8
|
+
const { dir: demoDir, style: demoStyle } = config.release.demo
|
|
8
9
|
|
|
9
10
|
console.log('🎨 Обновляю README релизами с демо...')
|
|
10
11
|
|
|
11
|
-
// Проверяем наличие файлов
|
|
12
12
|
if (!existsSync('CHANGELOG.md')) {
|
|
13
13
|
console.log('❌ CHANGELOG.md не найден')
|
|
14
14
|
console.log('💡 Сначала запусти: npm run _ changelog')
|
|
@@ -23,46 +23,70 @@ if (!existsSync('README.md')) {
|
|
|
23
23
|
const changelog = readFileSync('CHANGELOG.md', 'utf8')
|
|
24
24
|
let readme = readFileSync('README.md', 'utf8')
|
|
25
25
|
|
|
26
|
-
// Получаем
|
|
26
|
+
// Получаем URL репозитория
|
|
27
27
|
let repoUrl
|
|
28
28
|
try {
|
|
29
29
|
const remoteUrl = execSync('git config --get remote.origin.url').toString().trim()
|
|
30
30
|
if (remoteUrl.includes('github.com')) {
|
|
31
31
|
repoUrl = remoteUrl.replace('git@github.com:', 'https://github.com/').replace('.git', '')
|
|
32
32
|
}
|
|
33
|
-
} catch
|
|
33
|
+
} catch {
|
|
34
34
|
console.log('⚠️ Не удалось определить URL репозитория')
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
* Возвращает true если PNG
|
|
38
|
+
* Извлекает первый кадр GIF в PNG через sharp.
|
|
39
|
+
* Возвращает true если PNG создан успешно.
|
|
40
40
|
*/
|
|
41
|
-
function tryGeneratePng(gifPath, pngPath) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})
|
|
45
|
-
if (result.status === 0 && existsSync(pngPath)) {
|
|
41
|
+
async function tryGeneratePng(gifPath, pngPath) {
|
|
42
|
+
try {
|
|
43
|
+
await sharp(gifPath).png().toFile(pngPath)
|
|
46
44
|
console.log(`🖼️ PNG превью создан: ${pngPath}`)
|
|
47
45
|
return true
|
|
46
|
+
} catch {
|
|
47
|
+
return false
|
|
48
48
|
}
|
|
49
|
-
return false
|
|
50
49
|
}
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Генерирует HTML блок демо в зависимости от demoStyle.
|
|
53
|
+
*/
|
|
54
|
+
function renderDemo(version, gifPath, pngPath, hasGif, hasPng) {
|
|
55
|
+
if (demoStyle === 'side-by-side') {
|
|
56
|
+
let html = ''
|
|
57
|
+
if (hasPng) html += `<img src="${pngPath}" alt="${version} demo preview" width="400" />`
|
|
58
|
+
if (hasGif) html += `<img src="${gifPath}" alt="${version} demo animation" width="400" />`
|
|
59
|
+
return `**Демо работы** \n${html}\n\n`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 'click' (default) — PNG превью, клик открывает GIF
|
|
63
|
+
if (hasGif && hasPng) {
|
|
64
|
+
return (
|
|
65
|
+
`**Демо работы** \n` +
|
|
66
|
+
`<a href="${gifPath}"><img src="${pngPath}" alt="${version} demo preview" width="400" /></a>\n\n` +
|
|
67
|
+
`*${version} — нажми на превью чтобы увидеть анимацию*\n\n`
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
if (hasPng) {
|
|
71
|
+
return `**Демо работы** \n<img src="${pngPath}" alt="${version} demo preview" width="400" />\n\n`
|
|
72
|
+
}
|
|
73
|
+
return `**Демо работы** \n<img src="${gifPath}" alt="${version} demo" width="400" />\n\n`
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Парсим changelog — только версии с демо
|
|
53
77
|
const versionBlocks = changelog.split('## v').slice(1)
|
|
54
78
|
let prettyChangelog = '## 📋 История версий\n\n'
|
|
55
79
|
const processedVersions = new Set()
|
|
56
80
|
|
|
57
|
-
|
|
81
|
+
for (const versionBlock of versionBlocks) {
|
|
58
82
|
// Поддержка заголовков вида "v1.4.0...v2.0.0" (changelogen диапазон) и обычных "v2.0.0"
|
|
59
83
|
const rangeMatch = versionBlock.match(/^\d+\.\d+\.\d+\.\.\.v(\d+\.\d+\.\d+)/)
|
|
60
84
|
const simpleMatch = versionBlock.match(/^(\d+\.\d+\.\d+)/)
|
|
61
85
|
const versionMatch = rangeMatch || simpleMatch
|
|
62
|
-
if (!versionMatch)
|
|
86
|
+
if (!versionMatch) continue
|
|
63
87
|
|
|
64
88
|
const version = `v${versionMatch[1]}`
|
|
65
|
-
if (processedVersions.has(version))
|
|
89
|
+
if (processedVersions.has(version)) continue
|
|
66
90
|
processedVersions.add(version)
|
|
67
91
|
|
|
68
92
|
const gifPath = `${demoDir}/${version}.gif`
|
|
@@ -71,25 +95,25 @@ versionBlocks.forEach((versionBlock) => {
|
|
|
71
95
|
const hasGif = existsSync(gifPath)
|
|
72
96
|
let hasPng = existsSync(pngPath)
|
|
73
97
|
|
|
74
|
-
// Если есть GIF но нет PNG — пытаемся сгенерировать PNG через
|
|
98
|
+
// Если есть GIF но нет PNG — пытаемся сгенерировать PNG через sharp
|
|
75
99
|
if (hasGif && !hasPng) {
|
|
76
|
-
hasPng = tryGeneratePng(gifPath, pngPath)
|
|
100
|
+
hasPng = await tryGeneratePng(gifPath, pngPath)
|
|
77
101
|
}
|
|
78
102
|
|
|
79
103
|
const hasDemo = hasGif || hasPng
|
|
80
104
|
if (!hasDemo) {
|
|
81
105
|
console.log(`⏭️ Пропускаем ${version} - нет демо`)
|
|
82
|
-
|
|
106
|
+
continue
|
|
83
107
|
}
|
|
84
108
|
|
|
85
|
-
// Пропускаем если нет фич
|
|
109
|
+
// Пропускаем если нет фич
|
|
86
110
|
if (
|
|
87
111
|
!versionBlock.includes('### ✨ Новые фичи') &&
|
|
88
112
|
!versionBlock.includes('### ✨ Фичи') &&
|
|
89
113
|
!versionBlock.includes('### 🚀')
|
|
90
114
|
) {
|
|
91
115
|
console.log(`⏭️ Пропускаем ${version} - нет фич`)
|
|
92
|
-
|
|
116
|
+
continue
|
|
93
117
|
}
|
|
94
118
|
|
|
95
119
|
// Извлекаем фичи
|
|
@@ -98,7 +122,6 @@ versionBlocks.forEach((versionBlock) => {
|
|
|
98
122
|
let inFeaturesSection = false
|
|
99
123
|
|
|
100
124
|
for (const line of lines) {
|
|
101
|
-
// Поддержка разных форматов заголовков фич
|
|
102
125
|
if (line.includes('### ✨ Новые фичи') || line.includes('### ✨ Фичи') || line.includes('### 🚀')) {
|
|
103
126
|
inFeaturesSection = true
|
|
104
127
|
continue
|
|
@@ -119,38 +142,24 @@ versionBlocks.forEach((versionBlock) => {
|
|
|
119
142
|
}
|
|
120
143
|
}
|
|
121
144
|
|
|
122
|
-
if (features.length === 0)
|
|
145
|
+
if (features.length === 0) continue
|
|
123
146
|
|
|
124
147
|
console.log(`✅ Добавляем ${version} - есть демо и ${features.length} фич`)
|
|
125
148
|
|
|
126
|
-
// Форматируем версию
|
|
127
149
|
prettyChangelog += `### 🟢 ${version}\n\n`
|
|
150
|
+
prettyChangelog += renderDemo(version, gifPath, pngPath, hasGif, hasPng)
|
|
128
151
|
|
|
129
|
-
// Добавляем демо
|
|
130
|
-
// Если есть GIF + PNG → кликабельный превью (быстрая загрузка + анимация по клику)
|
|
131
|
-
// Если только PNG → обычный img
|
|
132
|
-
// Если только GIF → обычный img с GIF
|
|
133
|
-
if (hasGif && hasPng) {
|
|
134
|
-
prettyChangelog += `**Демо работы** \n<a href="${gifPath}" title="Нажми чтобы увидеть анимацию"><img src="${pngPath}" width="400" /></a>\n\n`
|
|
135
|
-
} else if (hasPng) {
|
|
136
|
-
prettyChangelog += `**Демо работы** \n<img src="${pngPath}" width="400" />\n\n`
|
|
137
|
-
} else {
|
|
138
|
-
prettyChangelog += `**Демо работы** \n<img src="${gifPath}" width="400" />\n\n`
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Добавляем функционал
|
|
142
152
|
prettyChangelog += `**Функционал:**\n`
|
|
143
153
|
features.forEach((feature) => {
|
|
144
154
|
prettyChangelog += `- ${feature}\n`
|
|
145
155
|
})
|
|
146
156
|
|
|
147
|
-
// Добавляем ссылку на релиз (если есть URL репозитория)
|
|
148
157
|
if (repoUrl) {
|
|
149
158
|
prettyChangelog += `\n**Релиз:** ${repoUrl}/releases/tag/${version}\n\n`
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
prettyChangelog += `---\n\n`
|
|
153
|
-
}
|
|
162
|
+
}
|
|
154
163
|
|
|
155
164
|
// Заменяем секцию между маркерами
|
|
156
165
|
if (readme.includes('<!-- AUTOGENERATED_SECTION START -->')) {
|
|
@@ -172,7 +181,6 @@ if (readme.includes('<!-- AUTOGENERATED_SECTION START -->')) {
|
|
|
172
181
|
process.exit(1)
|
|
173
182
|
}
|
|
174
183
|
|
|
175
|
-
// Сохраняем
|
|
176
184
|
writeFileSync('README.md', readme)
|
|
177
185
|
console.log('✅ README обновлён с релизами, у которых есть демо!')
|
|
178
186
|
|
|
@@ -187,6 +195,6 @@ try {
|
|
|
187
195
|
} else {
|
|
188
196
|
console.log('💡 README не изменился')
|
|
189
197
|
}
|
|
190
|
-
} catch
|
|
198
|
+
} catch {
|
|
191
199
|
console.log('💡 README обновлён локально (не удалось запушить автоматически)')
|
|
192
200
|
}
|