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