fg-devkit 1.6.8 → 1.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fg-devkit",
3
- "version": "1.6.8",
3
+ "version": "1.7.0",
4
4
  "description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -23,6 +23,7 @@
23
23
  "./cz-config": "./scripts/cz/.cz-config.cjs",
24
24
  "./scripts/sync-peers-from-dev.mjs": "./scripts/sync-peers-from-dev.mjs",
25
25
  "./scripts/sync-vscode-settings.mjs": "./scripts/sync-vscode-settings.mjs",
26
+ "./scripts/sync-core-coding-standards.mjs": "./scripts/sync-core-coding-standards.mjs",
26
27
  "./scripts/sync-tooling-configs.mjs": "./scripts/sync-tooling-configs.mjs",
27
28
  "./scripts/sync-project-configs.mjs": "./scripts/sync-project-configs.mjs",
28
29
  "./scripts/sync-consumer-scripts.mjs": "./scripts/sync-consumer-scripts.mjs",
@@ -34,7 +34,7 @@
34
34
  "@tanstack/vue-query-devtools": "6.1.24",
35
35
  "@types/node": "22.16.5",
36
36
  "@vitejs/plugin-vue": "6.0.6",
37
- "fg-devkit": "1.6.8",
37
+ "fg-devkit": "1.7.0",
38
38
  "start-server-and-test": "2.1.3",
39
39
  "tailwindcss": "4.2.4",
40
40
  "tsx": "4.21.0",
@@ -14,6 +14,7 @@
14
14
  * pnpm exec fg-devkit sync-project-configs (VS Code + tooling sync; overwrites config files)
15
15
  * pnpm exec fg-devkit sync-tooling-configs (tooling sync only; overwrites config files)
16
16
  * pnpm exec fg-devkit sync-vscode-settings
17
+ * pnpm exec fg-devkit sync-core-coding-standards
17
18
  * pnpm exec fg-devkit sync-consumer-scripts
18
19
  * pnpm exec fg-devkit setup-lefthook
19
20
  * pnpm exec fg-devkit prune-consumer-deps [--dry-run]
@@ -417,6 +418,7 @@ const DIRECT_COMMANDS = {
417
418
  'sync-project-configs': 'sync-project-configs.mjs',
418
419
  'sync-tooling-configs': 'sync-tooling-configs.mjs',
419
420
  'sync-vscode-settings': 'sync-vscode-settings.mjs',
421
+ 'sync-core-coding-standards': 'sync-core-coding-standards.mjs',
420
422
  'sync-consumer-scripts': 'sync-consumer-scripts.mjs',
421
423
  'setup-lefthook': 'setup-lefthook',
422
424
  'prune-consumer-deps': 'prune-consumer-deps.mjs',
@@ -444,6 +446,7 @@ Commands:
444
446
  sync-project-configs VS Code + tooling sync (overwrites config files)
445
447
  sync-tooling-configs Tooling sync only (overwrites config files)
446
448
  sync-vscode-settings Copy shared VS Code settings into .vscode/settings.json
449
+ sync-core-coding-standards Copy .cursor core coding standards with consumer package name
447
450
  sync-consumer-scripts Enforce standard fgd scripts in consumer package.json
448
451
  setup-lefthook Setup lefthook and migrate from husky/lint-staged
449
452
  prune-consumer-deps [--dry-run] Remove consumer tooling deps bundled by fg-devkit
@@ -528,6 +531,11 @@ const MENU = [
528
531
  label: 'PoEditor: Upload translations',
529
532
  run: () => runNode('poeditor-upload.mjs'),
530
533
  },
534
+ {
535
+ key: '12',
536
+ label: 'Sync .cursor core coding standards',
537
+ run: () => runNode('sync-core-coding-standards.mjs'),
538
+ },
531
539
  ]
532
540
 
533
541
  const MAINTAINER_MENU = [
@@ -8,21 +8,37 @@
8
8
  */
9
9
 
10
10
  import fs from 'node:fs'
11
+ import path from 'node:path'
11
12
 
12
13
  import { getFlagValue, getPoeditorToken, loadPoeditorConfig, parseFlags, resolvePathFromCwd } from './poeditor-common.mjs'
13
14
 
14
- async function uploadFile({ token, projectId, language, updating }) {
15
- const params = new URLSearchParams({
16
- api_token: token,
17
- id: String(projectId),
18
- language,
19
- updating,
20
- })
15
+ function getUploadType(filePath) {
16
+ const extension = path.extname(filePath).toLowerCase().replace('.', '')
17
+ if (!extension) {
18
+ throw new Error(`Cannot determine file type from "${filePath}"`)
19
+ }
20
+ if (extension === 'json') {
21
+ return 'key_value_json'
22
+ }
23
+ return extension
24
+ }
25
+
26
+ async function uploadFile({ token, projectId, language, filePath }) {
27
+ const fileBuffer = fs.readFileSync(filePath)
28
+ const fileName = path.basename(filePath)
29
+ const uploadType = getUploadType(filePath)
30
+ const form = new FormData()
31
+ form.append('api_token', token)
32
+ form.append('id', String(projectId))
33
+ form.append('updating', 'terms_translations')
34
+ form.append('language', language)
35
+ form.append('overwrite', '1')
36
+ form.append('type', uploadType)
37
+ form.append('file', new Blob([fileBuffer]), fileName)
21
38
 
22
39
  const res = await fetch('https://api.poeditor.com/v2/projects/upload', {
23
40
  method: 'POST',
24
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
25
- body: params,
41
+ body: form,
26
42
  })
27
43
  if (!res.ok) {
28
44
  throw new Error(`PoEditor upload failed (${res.status})`)
@@ -31,6 +47,10 @@ async function uploadFile({ token, projectId, language, updating }) {
31
47
  if (data?.response?.status !== 'success') {
32
48
  throw new Error(`Upload failed: ${JSON.stringify(data)}`)
33
49
  }
50
+ const translations = data?.result?.translations
51
+ console.log(
52
+ `[poeditor-upload] Upload complete for "${language}" (parsed: ${translations?.parsed ?? 0}, updated: ${translations?.updated ?? 0}, added: ${translations?.added ?? 0})`,
53
+ )
34
54
  }
35
55
 
36
56
  async function main() {
@@ -49,8 +69,7 @@ async function main() {
49
69
  if (hasExplicitLanguage || hasExplicitFile) {
50
70
  const language = getFlagValue(flags, 'language', cfg.defaultLanguage)
51
71
  const filePath = resolvePathFromCwd(getFlagValue(flags, 'file', cfg.uploadFile))
52
- const updating = fs.readFileSync(filePath, 'utf8')
53
- await uploadFile({ token, projectId, language, updating })
72
+ await uploadFile({ token, projectId, language, filePath })
54
73
  console.log(`[poeditor-upload] Upload completed for ${language}: ${filePath}`)
55
74
  return
56
75
  }
@@ -59,8 +78,7 @@ async function main() {
59
78
  if (uploads.length > 0) {
60
79
  for (const [language, file] of uploads) {
61
80
  const filePath = resolvePathFromCwd(file)
62
- const updating = fs.readFileSync(filePath, 'utf8')
63
- await uploadFile({ token, projectId, language, updating })
81
+ await uploadFile({ token, projectId, language, filePath })
64
82
  console.log(`[poeditor-upload] Upload completed for ${language}: ${filePath}`)
65
83
  }
66
84
  return
@@ -68,8 +86,7 @@ async function main() {
68
86
 
69
87
  const language = cfg.defaultLanguage
70
88
  const filePath = resolvePathFromCwd(cfg.uploadFile)
71
- const updating = fs.readFileSync(filePath, 'utf8')
72
- await uploadFile({ token, projectId, language, updating })
89
+ await uploadFile({ token, projectId, language, filePath })
73
90
  console.log(`[poeditor-upload] Upload completed for ${language}: ${filePath}`)
74
91
  }
75
92
 
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Syncs .cursor/rules/core-coding-standards.mdc into the consumer repo.
4
+ * Rewrites frontmatter description to include the consumer package name.
5
+ *
6
+ * Usage:
7
+ * node node_modules/fg-devkit/scripts/sync-core-coding-standards.mjs
8
+ * pnpm exec fg-devkit sync-core-coding-standards
9
+ */
10
+
11
+ import fs from 'node:fs'
12
+ import path from 'node:path'
13
+ import { fileURLToPath } from 'node:url'
14
+
15
+ const projectRoot = process.cwd()
16
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url))
17
+
18
+ function findFgDevkitPackageRoot() {
19
+ const candidates = [
20
+ path.resolve(scriptDir, '..'),
21
+ path.join(projectRoot, 'node_modules', 'fg-devkit'),
22
+ path.join(projectRoot, 'node_modules', 'fds-vue-core', 'node_modules', 'fg-devkit'),
23
+ ]
24
+ for (const p of candidates) {
25
+ if (fs.existsSync(path.join(p, 'package.json'))) {
26
+ return p
27
+ }
28
+ }
29
+ return null
30
+ }
31
+
32
+ function getConsumerPackageName() {
33
+ const pkgPath = path.join(projectRoot, 'package.json')
34
+ if (!fs.existsSync(pkgPath)) {
35
+ return 'consumer-project'
36
+ }
37
+ try {
38
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
39
+ if (typeof pkg.name === 'string' && pkg.name.trim() !== '') {
40
+ return pkg.name.trim()
41
+ }
42
+ } catch {
43
+ // fall through to default
44
+ }
45
+ return 'consumer-project'
46
+ }
47
+
48
+ const fgRoot = findFgDevkitPackageRoot()
49
+ if (!fgRoot) {
50
+ console.error(
51
+ '[sync-core-coding-standards] Could not find fg-devkit (install fg-devkit or a package that bundles it, e.g. fds-vue-core).',
52
+ )
53
+ process.exit(1)
54
+ }
55
+
56
+ const sourcePath = path.join(fgRoot, '.cursor', 'rules', 'core-coding-standards.mdc')
57
+ if (!fs.existsSync(sourcePath)) {
58
+ console.error('[sync-core-coding-standards] Missing source rule in fg-devkit package.')
59
+ process.exit(1)
60
+ }
61
+
62
+ const destinationPath = path.join(projectRoot, '.cursor', 'rules', 'core-coding-standards.mdc')
63
+ const packageName = getConsumerPackageName()
64
+
65
+ try {
66
+ const content = fs.readFileSync(sourcePath, 'utf8')
67
+ const updated = content.replace(
68
+ /^description:\s*.*$/m,
69
+ `description: Core coding standards for ${packageName}`,
70
+ )
71
+ fs.mkdirSync(path.dirname(destinationPath), { recursive: true })
72
+ fs.writeFileSync(destinationPath, updated, 'utf8')
73
+ console.log(`[sync-core-coding-standards] Updated ${destinationPath}`)
74
+ } catch (err) {
75
+ console.error(`[sync-core-coding-standards] ${err.message}`)
76
+ process.exit(1)
77
+ }