licenseguard-cli 2.2.0 → 2.3.1

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git remote:*)"
5
+ ]
6
+ }
7
+ }
package/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.3.0] - 2026-02-21
9
+
10
+ ### Added
11
+
12
+ - **ESM (ECMAScript Module) Support** - Git hooks now work in ESM projects
13
+ - Auto-detects ESM projects via `package.json` `"type": "module"`
14
+ - Generates ESM-compatible git hooks using `import` syntax for ESM projects
15
+ - Generates CommonJS hooks using `require` syntax for CJS projects
16
+ - `isEsmProject()` utility function for ESM detection
17
+ - ESM hook generators: `generatePostCheckoutScriptEsm()`, `generatePreCommitScriptEsm()`
18
+ - ESM global hooks in `postinstall.js` for `npm install -g` compatibility
19
+ - Full test coverage: 23 unit tests + 5 integration tests
20
+ - Backward compatible - existing CJS projects unaffected
21
+
8
22
  ## [2.2.0] - 2025-11-25
9
23
 
10
24
  ### Added
@@ -15,7 +15,10 @@ const templateDir = path.join(homeDir, '.git-templates')
15
15
  const hooksDir = path.join(templateDir, 'hooks')
16
16
 
17
17
  // Self-contained hook scripts (only needs Node.js, not licenseguard)
18
- const postCheckoutHook = `#!/usr/bin/env node
18
+
19
+ // CommonJS hook generators
20
+ function generatePostCheckoutHookCjs() {
21
+ return `#!/usr/bin/env node
19
22
  const fs = require('fs')
20
23
  const path = require('path')
21
24
 
@@ -33,8 +36,10 @@ try {
33
36
  }
34
37
  process.exit(0)
35
38
  `
39
+ }
36
40
 
37
- const preCommitHook = `#!/usr/bin/env node
41
+ function generatePreCommitHookCjs() {
42
+ return `#!/usr/bin/env node
38
43
  const fs = require('fs')
39
44
  const path = require('path')
40
45
 
@@ -52,6 +57,50 @@ try {
52
57
  }
53
58
  process.exit(0)
54
59
  `
60
+ }
61
+
62
+ // ESM hook generators
63
+ function generatePostCheckoutHookEsm() {
64
+ return `#!/usr/bin/env node
65
+ import fs from 'fs'
66
+ import path from 'path'
67
+
68
+ try {
69
+ const configPath = path.join(process.cwd(), '.licenseguardrc')
70
+ if (!fs.existsSync(configPath)) process.exit(0)
71
+
72
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
73
+ const blue = '\\x1b[34m'
74
+ const reset = '\\x1b[0m'
75
+
76
+ console.log(\`\${blue}📜 This project uses \${config.license.toUpperCase()} License by \${config.owner}\${reset}\`)
77
+ } catch (e) {
78
+ // Silent fail - never block git
79
+ }
80
+ process.exit(0)
81
+ `
82
+ }
83
+
84
+ function generatePreCommitHookEsm() {
85
+ return `#!/usr/bin/env node
86
+ import fs from 'fs'
87
+ import path from 'path'
88
+
89
+ try {
90
+ const configPath = path.join(process.cwd(), '.licenseguardrc')
91
+ if (!fs.existsSync(configPath)) process.exit(0)
92
+
93
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
94
+ const blue = '\\x1b[34m'
95
+ const reset = '\\x1b[0m'
96
+
97
+ console.log(\`\${blue}â„šī¸ Reminder: This project is licensed under \${config.license.toUpperCase()}\${reset}\`)
98
+ } catch (e) {
99
+ // Silent fail - never block git
100
+ }
101
+ process.exit(0)
102
+ `
103
+ }
55
104
 
56
105
  function setupGlobalHooks() {
57
106
  try {
@@ -68,6 +117,11 @@ function setupGlobalHooks() {
68
117
  return
69
118
  }
70
119
 
120
+ // Always use ESM for global hooks - ESM works in both ESM and CJS projects
121
+ // CJS hooks fail in ESM projects, but ESM hooks work everywhere
122
+ const postCheckoutHook = generatePostCheckoutHookEsm()
123
+ const preCommitHook = generatePreCommitHookEsm()
124
+
71
125
  // Create template directories
72
126
  if (!fs.existsSync(hooksDir)) {
73
127
  fs.mkdirSync(hooksDir, { recursive: true })
@@ -15,6 +15,22 @@ function isGitRepo() {
15
15
  }
16
16
  }
17
17
 
18
+ /**
19
+ * Check if current project is an ESM (ECMAScript Module) project
20
+ * @returns {boolean} true if package.json has "type": "module"
21
+ */
22
+ function isEsmProject() {
23
+ try {
24
+ if (!fs.existsSync('package.json')) {
25
+ return false
26
+ }
27
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'))
28
+ return pkg.type === 'module'
29
+ } catch (error) {
30
+ return false
31
+ }
32
+ }
33
+
18
34
  /**
19
35
  * Initialize a git repository in the current directory
20
36
  * @returns {boolean} true if git init succeeded
@@ -36,6 +52,7 @@ function initGitRepo() {
36
52
  function installHooks() {
37
53
  try {
38
54
  const hooksDir = path.join('.git', 'hooks')
55
+ const isEsm = isEsmProject()
39
56
 
40
57
  // Ensure hooks directory exists
41
58
  if (!fs.existsSync(hooksDir)) {
@@ -43,8 +60,8 @@ function installHooks() {
43
60
  }
44
61
 
45
62
  const hooks = [
46
- { name: 'post-checkout', script: generatePostCheckoutScript() },
47
- { name: 'pre-commit', script: generatePreCommitScript() },
63
+ { name: 'post-checkout', script: isEsm ? generatePostCheckoutScriptEsm() : generatePostCheckoutScript() },
64
+ { name: 'pre-commit', script: isEsm ? generatePreCommitScriptEsm() : generatePreCommitScript() },
48
65
  ]
49
66
 
50
67
  let hasConflicts = false
@@ -167,8 +184,91 @@ try {
167
184
  `
168
185
  }
169
186
 
187
+ /**
188
+ * Generate post-checkout hook script (ESM version)
189
+ * @returns {string} Hook script content
190
+ */
191
+ function generatePostCheckoutScriptEsm() {
192
+ return `#!/usr/bin/env node
193
+ import fs from 'fs'
194
+ import path from 'path'
195
+ import { fileURLToPath } from 'url'
196
+
197
+ const __filename = fileURLToPath(import.meta.url)
198
+ const __dirname = path.dirname(__filename)
199
+
200
+ try {
201
+ // Read .licenseguardrc from project root (relative to .git/hooks/)
202
+ const configPath = path.resolve(__dirname, '..', '..', '.licenseguardrc')
203
+
204
+ if (!fs.existsSync(configPath)) {
205
+ // No config file, silently exit
206
+ process.exit(0)
207
+ }
208
+
209
+ const configContent = fs.readFileSync(configPath, 'utf8')
210
+ const config = JSON.parse(configContent)
211
+
212
+ // Display license notification with color
213
+ const blue = '\\x1b[34m'
214
+ const reset = '\\x1b[0m'
215
+
216
+ console.log(\`\${blue}📜 This project uses \${config.license.toUpperCase()} License by \${config.owner}\${reset}\`)
217
+
218
+ process.exit(0)
219
+ } catch (error) {
220
+ // Errors should not block git operations
221
+ process.exit(0)
222
+ }
223
+ `
224
+ }
225
+
226
+ /**
227
+ * Generate pre-commit hook script (ESM version)
228
+ * @returns {string} Hook script content
229
+ */
230
+ function generatePreCommitScriptEsm() {
231
+ return `#!/usr/bin/env node
232
+ import fs from 'fs'
233
+ import path from 'path'
234
+ import { fileURLToPath } from 'url'
235
+
236
+ const __filename = fileURLToPath(import.meta.url)
237
+ const __dirname = path.dirname(__filename)
238
+
239
+ try {
240
+ // Read .licenseguardrc from project root (relative to .git/hooks/)
241
+ const configPath = path.resolve(__dirname, '..', '..', '.licenseguardrc')
242
+
243
+ if (!fs.existsSync(configPath)) {
244
+ // No config file, silently exit
245
+ process.exit(0)
246
+ }
247
+
248
+ const configContent = fs.readFileSync(configPath, 'utf8')
249
+ const config = JSON.parse(configContent)
250
+
251
+ // Display license reminder with color
252
+ const blue = '\\x1b[34m'
253
+ const reset = '\\x1b[0m'
254
+
255
+ console.log(\`\${blue}â„šī¸ Reminder: This project is licensed under \${config.license.toUpperCase()}\${reset}\`)
256
+
257
+ process.exit(0)
258
+ } catch (error) {
259
+ // Errors should not block git operations
260
+ process.exit(0)
261
+ }
262
+ `
263
+ }
264
+
170
265
  module.exports = {
171
266
  isGitRepo,
172
267
  initGitRepo,
173
268
  installHooks,
269
+ isEsmProject,
270
+ generatePostCheckoutScript,
271
+ generatePreCommitScript,
272
+ generatePostCheckoutScriptEsm,
273
+ generatePreCommitScriptEsm,
174
274
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "licenseguard-cli",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
4
4
  "description": "License setup & compliance guard for developers",
5
5
  "bin": {
6
6
  "licenseguard": "bin/licenseguard.js"