fg-devkit 1.6.7 → 1.6.9

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.7",
3
+ "version": "1.6.9",
4
4
  "description": "Shared configs, scripts, and DX tooling for Vue / TypeScript frontend repos",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -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.7",
37
+ "fg-devkit": "1.6.9",
38
38
  "start-server-and-test": "2.1.3",
39
39
  "tailwindcss": "4.2.4",
40
40
  "tsx": "4.21.0",
@@ -10,6 +10,34 @@ function readJsonIfExists(filePath) {
10
10
  }
11
11
  }
12
12
 
13
+ function readEnvValueFromFile(filePath, key) {
14
+ if (!fs.existsSync(filePath)) return ''
15
+ try {
16
+ const raw = fs.readFileSync(filePath, 'utf8')
17
+ const lines = raw.split(/\r?\n/)
18
+ for (const line of lines) {
19
+ const trimmed = line.trim()
20
+ if (!trimmed || trimmed.startsWith('#')) continue
21
+ const noExport = trimmed.startsWith('export ') ? trimmed.slice(7).trim() : trimmed
22
+ const eqIdx = noExport.indexOf('=')
23
+ if (eqIdx <= 0) continue
24
+ const k = noExport.slice(0, eqIdx).trim()
25
+ if (k !== key) continue
26
+ let value = noExport.slice(eqIdx + 1).trim()
27
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
28
+ value = value.slice(1, -1)
29
+ } else {
30
+ const hashIdx = value.indexOf(' #')
31
+ if (hashIdx >= 0) value = value.slice(0, hashIdx).trim()
32
+ }
33
+ return value
34
+ }
35
+ } catch {
36
+ return ''
37
+ }
38
+ return ''
39
+ }
40
+
13
41
  function resolveFromCwd(p) {
14
42
  return path.isAbsolute(p) ? p : path.resolve(process.cwd(), p)
15
43
  }
@@ -112,6 +140,12 @@ export function getPoeditorToken(flags) {
112
140
  const fromFlag = getFlagValue(flags, 'api-token')
113
141
  if (fromFlag) return fromFlag
114
142
  if (process.env.POEDITOR_API_KEY) return process.env.POEDITOR_API_KEY
143
+ const plainEnvLocal = readEnvValueFromFile(resolveFromCwd('./env.local'), 'POEDITOR_API_KEY')
144
+ if (plainEnvLocal) return plainEnvLocal
145
+ const envLocal = readEnvValueFromFile(resolveFromCwd('./.env.local'), 'POEDITOR_API_KEY')
146
+ if (envLocal) return envLocal
147
+ const envFile = readEnvValueFromFile(resolveFromCwd('./.env'), 'POEDITOR_API_KEY')
148
+ if (envFile) return envFile
115
149
  const publicConfigPath = resolveFromCwd('./public/config.json')
116
150
  const publicConfig = readJsonIfExists(publicConfigPath)
117
151
  if (typeof publicConfig?.POEDITOR_API_KEY === 'string') {
@@ -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