@diia-inhouse/genproto 3.3.1 → 4.0.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/LICENCE.md +59 -59
- package/dist/command/index.js +11 -19
- package/dist/command/index.js.map +1 -1
- package/dist/command/javaCommandBuilder.js +2 -5
- package/dist/command/javaCommandBuilder.js.map +1 -1
- package/dist/command/pythonCommandBuilder.js +43 -53
- package/dist/command/pythonCommandBuilder.js.map +1 -1
- package/dist/command/tsCommandBuilder.js +65 -74
- package/dist/command/tsCommandBuilder.js.map +1 -1
- package/dist/genproto.js +31 -36
- package/dist/genproto.js.map +1 -1
- package/dist/logger.js +3 -6
- package/dist/logger.js.map +1 -1
- package/dist/types/command/index.d.ts +1 -1
- package/dist/types/command/javaCommandBuilder.d.ts +1 -1
- package/dist/types/command/pythonCommandBuilder.d.ts +3 -1
- package/dist/types/command/tsCommandBuilder.d.ts +3 -2
- package/dist/utils/index.js +29 -77
- package/dist/utils/index.js.map +1 -1
- package/package.json +28 -20
- package/src/command/index.ts +2 -3
- package/src/command/javaCommandBuilder.ts +1 -1
- package/src/command/pythonCommandBuilder.ts +24 -28
- package/src/command/tsCommandBuilder.ts +52 -55
- package/src/genproto.ts +10 -10
- package/src/logger.ts +2 -2
- package/src/utils/index.ts +16 -20
package/package.json
CHANGED
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diia-inhouse/genproto",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "JS codegen from proto with imports from @diia-inhouse/types",
|
|
5
6
|
"bin": {
|
|
6
7
|
"genproto": "./dist/genproto.js"
|
|
7
8
|
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/types/genproto.d.ts",
|
|
12
|
+
"default": "./dist/genproto.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
8
16
|
"repository": "https://github.com/diia-open-source/be-genproto",
|
|
9
17
|
"scripts": {
|
|
10
18
|
"prebuild": "rimraf dist",
|
|
11
19
|
"build": "tsc",
|
|
12
20
|
"build:watch": "tsc --watch",
|
|
13
21
|
"semantic-release": "semantic-release",
|
|
14
|
-
"lint": "
|
|
15
|
-
"lint-fix": "
|
|
22
|
+
"lint": "oxlint && oxfmt --check .",
|
|
23
|
+
"lint-fix": "oxlint --fix && oxfmt .",
|
|
16
24
|
"lint:lockfile": "lockfile-lint --path package-lock.json --allowed-hosts registry.npmjs.org --validate-https",
|
|
17
25
|
"prepare": "npm run build",
|
|
18
26
|
"test": "tsc --project tests/tsconfig.json && vitest run",
|
|
19
27
|
"find-circulars": "madge --circular --extensions ts ./"
|
|
20
28
|
},
|
|
21
29
|
"engines": {
|
|
22
|
-
"node": ">=
|
|
30
|
+
"node": ">=24"
|
|
23
31
|
},
|
|
24
32
|
"author": "Diia",
|
|
25
33
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -28,28 +36,29 @@
|
|
|
28
36
|
"src"
|
|
29
37
|
],
|
|
30
38
|
"dependencies": {
|
|
31
|
-
"glob": "
|
|
39
|
+
"glob": "13.0.6",
|
|
32
40
|
"lodash": "4.18.1",
|
|
33
|
-
"lookpath": "1.2.
|
|
34
|
-
"yargs": "
|
|
41
|
+
"lookpath": "1.2.3",
|
|
42
|
+
"yargs": "18.0.0"
|
|
35
43
|
},
|
|
36
44
|
"peerDependencies": {
|
|
37
45
|
"ts-proto": ">=2.7.0"
|
|
38
46
|
},
|
|
39
47
|
"devDependencies": {
|
|
40
|
-
"@diia-inhouse/configs": "
|
|
41
|
-
"@diia-inhouse/
|
|
48
|
+
"@diia-inhouse/configs": "7.0.0",
|
|
49
|
+
"@diia-inhouse/oxc-config": "1.9.3",
|
|
42
50
|
"@types/lodash": "4.17.24",
|
|
43
|
-
"@types/node": "
|
|
44
|
-
"@types/yargs": "17.0.
|
|
45
|
-
"@vitest/coverage-v8": "4.1.
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
51
|
+
"@types/node": "25.6.2",
|
|
52
|
+
"@types/yargs": "17.0.35",
|
|
53
|
+
"@vitest/coverage-v8": "4.1.5",
|
|
54
|
+
"lockfile-lint": "5.0.0",
|
|
55
|
+
"madge": "8.0.0",
|
|
56
|
+
"oxfmt": "0.48.0",
|
|
57
|
+
"oxlint": "1.63.0",
|
|
58
|
+
"oxlint-tsgolint": "0.22.1",
|
|
59
|
+
"rimraf": "6.1.3",
|
|
60
|
+
"semantic-release": "25.0.3",
|
|
61
|
+
"vitest": "4.1.5"
|
|
53
62
|
},
|
|
54
63
|
"release": {
|
|
55
64
|
"extends": "@diia-inhouse/configs/dist/semantic-release/package"
|
|
@@ -57,7 +66,6 @@
|
|
|
57
66
|
"commitlint": {
|
|
58
67
|
"extends": "@diia-inhouse/configs/dist/commitlint"
|
|
59
68
|
},
|
|
60
|
-
"prettier": "@diia-inhouse/eslint-config/prettier",
|
|
61
69
|
"madge": {
|
|
62
70
|
"tsConfig": "./tsconfig.json"
|
|
63
71
|
}
|
package/src/command/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path'
|
|
|
3
3
|
|
|
4
4
|
import { glob } from 'glob'
|
|
5
5
|
|
|
6
|
-
import Logger from '../logger'
|
|
6
|
+
import Logger from '../logger.js'
|
|
7
7
|
|
|
8
8
|
export enum Platform {
|
|
9
9
|
ts = 'ts',
|
|
@@ -25,7 +25,7 @@ export abstract class CommandBuilder {
|
|
|
25
25
|
const protoFiles = await glob(`${this.rootDir}/**/*.proto`, { ignore: '**/node_modules/**' })
|
|
26
26
|
|
|
27
27
|
if (protoFiles.length > 0) {
|
|
28
|
-
iPath +=
|
|
28
|
+
iPath += ` ${protoFiles.join(' ')}`
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
return iPath.trim()
|
|
@@ -61,7 +61,6 @@ export abstract class CommandBuilder {
|
|
|
61
61
|
return acc
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
65
64
|
const contents = fs.readFileSync(value) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
66
65
|
if (!contents.includes('package ua.gov.diia')) {
|
|
67
66
|
return acc
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
2
1
|
import { once } from 'node:events'
|
|
3
2
|
import { WriteStream, createWriteStream, existsSync } from 'node:fs'
|
|
4
3
|
import fsPromises from 'node:fs/promises'
|
|
@@ -6,16 +5,16 @@ import path from 'node:path'
|
|
|
6
5
|
import { finished } from 'node:stream/promises'
|
|
7
6
|
|
|
8
7
|
import { glob } from 'glob'
|
|
9
|
-
import
|
|
8
|
+
import snakeCase from 'lodash/snakeCase.js'
|
|
10
9
|
|
|
11
|
-
import Logger from '../logger'
|
|
12
|
-
import { CommandBuilder } from './index'
|
|
13
|
-
|
|
14
|
-
// import "designSystem/molecules/attentionIconMessageMlc.proto";
|
|
15
|
-
const importRegex = /import "(?<path>[^"]+)";/
|
|
16
|
-
const slashPrefix = /^\/+/
|
|
10
|
+
import Logger from '../logger.js'
|
|
11
|
+
import { CommandBuilder } from './index.js'
|
|
17
12
|
|
|
18
13
|
export default class PythonCommandBuilder extends CommandBuilder {
|
|
14
|
+
// import "designSystem/molecules/attentionIconMessageMlc.proto";
|
|
15
|
+
static readonly importRegex = /import "(?<path>[^"]+)";/
|
|
16
|
+
static readonly slashPrefix = /^\/+/
|
|
17
|
+
|
|
19
18
|
private cardinalDependencies: Record<string, string> = {
|
|
20
19
|
'node_modules/@diia-inhouse/types/dist/proto': 'types_proto',
|
|
21
20
|
'node_modules/@diia-inhouse/design-system/dist/proto': 'design_system_proto',
|
|
@@ -33,8 +32,8 @@ export default class PythonCommandBuilder extends CommandBuilder {
|
|
|
33
32
|
'--proto_path=node_modules/protobufjs/google',
|
|
34
33
|
'--proto_path=/usr/local/include',
|
|
35
34
|
...Object.keys(this.cardinalDependencies)
|
|
36
|
-
.filter((
|
|
37
|
-
.map((
|
|
35
|
+
.filter((depPath) => existsSync(depPath)) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
36
|
+
.map((depPath) => `--proto_path=${depPath}`),
|
|
38
37
|
]
|
|
39
38
|
|
|
40
39
|
for (const protoPath of this.protoPaths) {
|
|
@@ -71,7 +70,7 @@ export default class PythonCommandBuilder extends CommandBuilder {
|
|
|
71
70
|
const files = await glob(dep + protoPattern)
|
|
72
71
|
|
|
73
72
|
for (const file of files) {
|
|
74
|
-
const res = file.replace(dep, '').replace(slashPrefix, '')
|
|
73
|
+
const res = file.replace(dep, '').replace(PythonCommandBuilder.slashPrefix, '')
|
|
75
74
|
|
|
76
75
|
mapping[res] = this.cardinalDependencies[dep]
|
|
77
76
|
|
|
@@ -79,7 +78,7 @@ export default class PythonCommandBuilder extends CommandBuilder {
|
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
const localProtos = await glob(
|
|
81
|
+
const localProtos = await glob(`proto${protoPattern}`)
|
|
83
82
|
|
|
84
83
|
const rulesTasks = []
|
|
85
84
|
for (const localProto of localProtos) {
|
|
@@ -90,7 +89,7 @@ export default class PythonCommandBuilder extends CommandBuilder {
|
|
|
90
89
|
|
|
91
90
|
replaceRules = [...new Map(rules.flat().map((rule) => [rule.regex.source, rule])).values()]
|
|
92
91
|
|
|
93
|
-
const generatedFiles = await glob(this.outputDir
|
|
92
|
+
const generatedFiles = await glob(`${this.outputDir}/**/*.py`)
|
|
94
93
|
|
|
95
94
|
const tasks: Promise<void>[] = []
|
|
96
95
|
for (const generatedFile of generatedFiles) {
|
|
@@ -119,7 +118,7 @@ async function touchFilesInTree(dirPath: string, fileName: string, logger: Logge
|
|
|
119
118
|
await handle.utimes(new Date(), new Date()) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
120
119
|
await handle.close()
|
|
121
120
|
} catch (err) {
|
|
122
|
-
logger.log(`Could not touch file in ${dirPath}: ${err instanceof Error ? err.message : err}`)
|
|
121
|
+
logger.log(`Could not touch file in ${dirPath}: ${err instanceof Error ? err.message : String(err)}`)
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
for (const entry of entries) {
|
|
@@ -149,7 +148,6 @@ async function replaceRulesTask(
|
|
|
149
148
|
const protoFilenameSnakeImportAlies = doubleInnerUnderscores(protoFilenameSnake)
|
|
150
149
|
|
|
151
150
|
if (protoDirname === 'proto') {
|
|
152
|
-
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
153
151
|
const rootImportRegex = new RegExp( // nosemgrep: eslint.detect-non-literal-regexp
|
|
154
152
|
`^${escapeRegex(`import ${protoFilenameSnake}_pb2 as ${protoFilenameSnakeImportAlies}__pb2`)}`,
|
|
155
153
|
)
|
|
@@ -161,7 +159,7 @@ async function replaceRulesTask(
|
|
|
161
159
|
}
|
|
162
160
|
|
|
163
161
|
for await (const line of handle.readLines()) {
|
|
164
|
-
const result = importRegex.exec(line)
|
|
162
|
+
const result = PythonCommandBuilder.importRegex.exec(line)
|
|
165
163
|
const importPath = result?.groups?.path
|
|
166
164
|
|
|
167
165
|
if (importPath === undefined) {
|
|
@@ -175,13 +173,12 @@ async function replaceRulesTask(
|
|
|
175
173
|
const depname = mapping[importPath]
|
|
176
174
|
|
|
177
175
|
if (depname === undefined) {
|
|
178
|
-
logger.log(`Looking for ${importPath} in mapper, received
|
|
176
|
+
logger.log(`Looking for ${importPath} in mapper, received undefined. Skipping the mapper.`)
|
|
179
177
|
continue
|
|
180
178
|
}
|
|
181
179
|
|
|
182
180
|
logger.log(`I'm looking for ${fileName} (${fileName}) to map as "import ${fileName}_pb2"`)
|
|
183
181
|
|
|
184
|
-
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
185
182
|
const flatImportRegex = new RegExp(`^${escapeRegex(`import ${fileName}_pb2`)}`) // nosemgrep: eslint.detect-non-literal-regexp
|
|
186
183
|
|
|
187
184
|
replaceRules.push({
|
|
@@ -192,7 +189,7 @@ async function replaceRulesTask(
|
|
|
192
189
|
const depname = mapping[importPath]
|
|
193
190
|
|
|
194
191
|
if (depname === undefined) {
|
|
195
|
-
logger.log(`Looking for ${importPath} in mapper, received
|
|
192
|
+
logger.log(`Looking for ${importPath} in mapper, received undefined. Skipping the mapper.`)
|
|
196
193
|
continue
|
|
197
194
|
}
|
|
198
195
|
|
|
@@ -200,7 +197,6 @@ async function replaceRulesTask(
|
|
|
200
197
|
|
|
201
198
|
logger.log(`I'm looking for ${fileName} (${fileName}) to map as "from ${importName} import ${fileName}_pb2"`)
|
|
202
199
|
|
|
203
|
-
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
204
200
|
const nestedImportRegex = new RegExp(`^${escapeRegex(`from ${importName} import ${fileName}_pb2`)}`) // nosemgrep: eslint.detect-non-literal-regexp
|
|
205
201
|
|
|
206
202
|
replaceRules.push({
|
|
@@ -225,7 +221,7 @@ async function fileMapper(generatedFile: string, replaceRules: { regex: RegExp;
|
|
|
225
221
|
try {
|
|
226
222
|
handle = await fsPromises.open(generatedFile) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
227
223
|
|
|
228
|
-
wstream = createWriteStream(generatedFile
|
|
224
|
+
wstream = createWriteStream(`${generatedFile}.new`) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
229
225
|
|
|
230
226
|
for await (const line of handle.readLines()) {
|
|
231
227
|
let mutableLine = line
|
|
@@ -233,7 +229,7 @@ async function fileMapper(generatedFile: string, replaceRules: { regex: RegExp;
|
|
|
233
229
|
mutableLine = mutableLine.replace(rule.regex, rule.to)
|
|
234
230
|
}
|
|
235
231
|
|
|
236
|
-
const writeOk = wstream.write(mutableLine
|
|
232
|
+
const writeOk = wstream.write(`${mutableLine}\n`)
|
|
237
233
|
|
|
238
234
|
if (!writeOk) {
|
|
239
235
|
await once(wstream, 'drain')
|
|
@@ -251,22 +247,22 @@ async function fileMapper(generatedFile: string, replaceRules: { regex: RegExp;
|
|
|
251
247
|
await finished(wstream)
|
|
252
248
|
|
|
253
249
|
// nosemgrep: eslint.detect-non-literal-fs-filename
|
|
254
|
-
if (!isOk && existsSync(generatedFile
|
|
255
|
-
await fsPromises.unlink(generatedFile
|
|
250
|
+
if (!isOk && existsSync(`${generatedFile}.new`)) {
|
|
251
|
+
await fsPromises.unlink(`${generatedFile}.new`) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
256
252
|
}
|
|
257
253
|
}
|
|
258
254
|
}
|
|
259
255
|
|
|
260
256
|
try {
|
|
261
|
-
await fsPromises.rename(generatedFile
|
|
257
|
+
await fsPromises.rename(`${generatedFile}.new`, generatedFile) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
262
258
|
logger.log('Update successful!')
|
|
263
259
|
} catch (err) {
|
|
264
260
|
// nosemgrep: eslint.detect-non-literal-fs-filename
|
|
265
|
-
if (existsSync(generatedFile
|
|
266
|
-
await fsPromises.unlink(generatedFile
|
|
261
|
+
if (existsSync(`${generatedFile}.new`)) {
|
|
262
|
+
await fsPromises.unlink(`${generatedFile}.new`) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
267
263
|
}
|
|
268
264
|
|
|
269
|
-
logger.log(`Final swap failed: ${err}`)
|
|
265
|
+
logger.log(`Final swap failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
270
266
|
throw err
|
|
271
267
|
}
|
|
272
268
|
}
|
|
@@ -4,58 +4,58 @@ import path from 'node:path'
|
|
|
4
4
|
|
|
5
5
|
import { glob } from 'glob'
|
|
6
6
|
|
|
7
|
-
import Logger from '../logger'
|
|
8
|
-
import { CommandBuilder, Platform } from './index'
|
|
9
|
-
|
|
10
|
-
const reservedWords = new Set([
|
|
11
|
-
'break',
|
|
12
|
-
'case',
|
|
13
|
-
'catch',
|
|
14
|
-
'class',
|
|
15
|
-
'const',
|
|
16
|
-
'continue',
|
|
17
|
-
'debugger',
|
|
18
|
-
'default',
|
|
19
|
-
'delete',
|
|
20
|
-
'do',
|
|
21
|
-
'else',
|
|
22
|
-
'enum',
|
|
23
|
-
'export',
|
|
24
|
-
'extends',
|
|
25
|
-
'false',
|
|
26
|
-
'finally',
|
|
27
|
-
'for',
|
|
28
|
-
'function',
|
|
29
|
-
'if',
|
|
30
|
-
'import',
|
|
31
|
-
'in',
|
|
32
|
-
'instanceof',
|
|
33
|
-
'new',
|
|
34
|
-
'null',
|
|
35
|
-
'return',
|
|
36
|
-
'super',
|
|
37
|
-
'switch',
|
|
38
|
-
'this',
|
|
39
|
-
'throw',
|
|
40
|
-
'true',
|
|
41
|
-
'try',
|
|
42
|
-
'typeof',
|
|
43
|
-
'var',
|
|
44
|
-
'void',
|
|
45
|
-
'while',
|
|
46
|
-
'with',
|
|
47
|
-
'yield',
|
|
48
|
-
'let',
|
|
49
|
-
'static',
|
|
50
|
-
'implements',
|
|
51
|
-
'interface',
|
|
52
|
-
'package',
|
|
53
|
-
'private',
|
|
54
|
-
'protected',
|
|
55
|
-
'public',
|
|
56
|
-
])
|
|
7
|
+
import Logger from '../logger.js'
|
|
8
|
+
import { CommandBuilder, Platform } from './index.js'
|
|
57
9
|
|
|
58
10
|
export default class TsCommandBuilder extends CommandBuilder {
|
|
11
|
+
private static readonly reservedWords = new Set([
|
|
12
|
+
'break',
|
|
13
|
+
'case',
|
|
14
|
+
'catch',
|
|
15
|
+
'class',
|
|
16
|
+
'const',
|
|
17
|
+
'continue',
|
|
18
|
+
'debugger',
|
|
19
|
+
'default',
|
|
20
|
+
'delete',
|
|
21
|
+
'do',
|
|
22
|
+
'else',
|
|
23
|
+
'enum',
|
|
24
|
+
'export',
|
|
25
|
+
'extends',
|
|
26
|
+
'false',
|
|
27
|
+
'finally',
|
|
28
|
+
'for',
|
|
29
|
+
'function',
|
|
30
|
+
'if',
|
|
31
|
+
'import',
|
|
32
|
+
'in',
|
|
33
|
+
'instanceof',
|
|
34
|
+
'new',
|
|
35
|
+
'null',
|
|
36
|
+
'return',
|
|
37
|
+
'super',
|
|
38
|
+
'switch',
|
|
39
|
+
'this',
|
|
40
|
+
'throw',
|
|
41
|
+
'true',
|
|
42
|
+
'try',
|
|
43
|
+
'typeof',
|
|
44
|
+
'var',
|
|
45
|
+
'void',
|
|
46
|
+
'while',
|
|
47
|
+
'with',
|
|
48
|
+
'yield',
|
|
49
|
+
'let',
|
|
50
|
+
'static',
|
|
51
|
+
'implements',
|
|
52
|
+
'interface',
|
|
53
|
+
'package',
|
|
54
|
+
'private',
|
|
55
|
+
'protected',
|
|
56
|
+
'public',
|
|
57
|
+
])
|
|
58
|
+
|
|
59
59
|
// By default ts plugin should be linked to .bin dir but in case if it doesn't
|
|
60
60
|
// try to look it up in "standard" locations
|
|
61
61
|
private tsPluginLocations = [
|
|
@@ -80,7 +80,6 @@ export default class TsCommandBuilder extends CommandBuilder {
|
|
|
80
80
|
|
|
81
81
|
for (const location of this.tsPluginLocations) {
|
|
82
82
|
try {
|
|
83
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
84
83
|
await fs.realpath(location) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
85
84
|
} catch {
|
|
86
85
|
continue
|
|
@@ -115,7 +114,7 @@ export default class TsCommandBuilder extends CommandBuilder {
|
|
|
115
114
|
switch (projectPlatform) {
|
|
116
115
|
case Platform.java: {
|
|
117
116
|
typesProtoPath = `./${this.javaModule ?? '.'}/build/extracted-protos/main/`
|
|
118
|
-
typesSubPaths = [
|
|
117
|
+
typesSubPaths = [this.javaModule ?? '.', 'build', 'extracted-protos', 'main']
|
|
119
118
|
dependenciesPattern = `${this.javaModule ?? '.'}/build/extracted-protos/main/**/*.proto`
|
|
120
119
|
execSync(`./gradlew ${this.javaModule ?? ''}:extractProto`, { stdio: 'pipe' })
|
|
121
120
|
break
|
|
@@ -187,7 +186,6 @@ export default class TsCommandBuilder extends CommandBuilder {
|
|
|
187
186
|
const files = await glob(path.join(this.outputDir, '**/*.ts'))
|
|
188
187
|
|
|
189
188
|
for (const file of files) {
|
|
190
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
191
189
|
const content = await fs.readFile(file, 'utf8') // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
192
190
|
|
|
193
191
|
if (!content.includes('export namespace ')) {
|
|
@@ -197,7 +195,6 @@ export default class TsCommandBuilder extends CommandBuilder {
|
|
|
197
195
|
const result = this.stripReservedWordTypeAliases(content)
|
|
198
196
|
|
|
199
197
|
if (result !== content) {
|
|
200
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
201
198
|
await fs.writeFile(file, result) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
202
199
|
}
|
|
203
200
|
}
|
|
@@ -235,7 +232,7 @@ export default class TsCommandBuilder extends CommandBuilder {
|
|
|
235
232
|
if (insideNamespace) {
|
|
236
233
|
const match = line.match(/^\s*export type (\w+) = typeof /)
|
|
237
234
|
|
|
238
|
-
if (match && reservedWords.has(match[1])) {
|
|
235
|
+
if (match && TsCommandBuilder.reservedWords.has(match[1])) {
|
|
239
236
|
continue
|
|
240
237
|
}
|
|
241
238
|
|
package/src/genproto.ts
CHANGED
|
@@ -5,13 +5,14 @@ import path from 'node:path'
|
|
|
5
5
|
|
|
6
6
|
import { lookpath } from 'lookpath'
|
|
7
7
|
import yargs from 'yargs'
|
|
8
|
+
import { hideBin } from 'yargs/helpers'
|
|
8
9
|
|
|
9
|
-
import { CommandBuilder, Platform } from './command'
|
|
10
|
-
import JavaCommandBuilder from './command/javaCommandBuilder'
|
|
11
|
-
import PythonCommandBuilder from './command/pythonCommandBuilder'
|
|
12
|
-
import TsCommandBuilder from './command/tsCommandBuilder'
|
|
13
|
-
import Logger from './logger'
|
|
14
|
-
import Utils from './utils'
|
|
10
|
+
import { CommandBuilder, Platform } from './command/index.js'
|
|
11
|
+
import JavaCommandBuilder from './command/javaCommandBuilder.js'
|
|
12
|
+
import PythonCommandBuilder from './command/pythonCommandBuilder.js'
|
|
13
|
+
import TsCommandBuilder from './command/tsCommandBuilder.js'
|
|
14
|
+
import Logger from './logger.js'
|
|
15
|
+
import Utils from './utils/index.js'
|
|
15
16
|
|
|
16
17
|
async function main(): Promise<void> {
|
|
17
18
|
const protocExists = await lookpath('protoc')
|
|
@@ -20,7 +21,7 @@ async function main(): Promise<void> {
|
|
|
20
21
|
throw new Error("Couldn't find protoc in PATH")
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
const options = await yargs
|
|
24
|
+
const options = await yargs(hideBin(process.argv))
|
|
24
25
|
.usage('$0 --rootDir dirname --outputDir dirname')
|
|
25
26
|
.option('v', { type: 'boolean', default: false })
|
|
26
27
|
.option('platform', { type: 'string', default: Platform.ts })
|
|
@@ -51,12 +52,11 @@ async function main(): Promise<void> {
|
|
|
51
52
|
|
|
52
53
|
logger.log(`Creating directory ${outputAbsoluteDir}...`)
|
|
53
54
|
|
|
54
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
55
55
|
await fs.promises.mkdir(outputDir, { recursive: true }) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
56
56
|
|
|
57
57
|
let commandBuilder: CommandBuilder
|
|
58
58
|
|
|
59
|
-
switch (platform) {
|
|
59
|
+
switch (platform as Platform) {
|
|
60
60
|
case Platform.java: {
|
|
61
61
|
commandBuilder = new JavaCommandBuilder(logger, generateClient, rootDir, outputDir, protoPaths)
|
|
62
62
|
break
|
|
@@ -91,7 +91,7 @@ async function main(): Promise<void> {
|
|
|
91
91
|
logger.log(`Generating index.ts for directory: ${indexDir}`)
|
|
92
92
|
await Utils.generateIndexForDirectory(indexDir, rootDir)
|
|
93
93
|
} catch (err) {
|
|
94
|
-
logger.log(`Error processing directory ${dir}: ${err}`)
|
|
94
|
+
logger.log(`Error processing directory ${dir}: ${err instanceof Error ? err.message : String(err)}`)
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
}
|
package/src/logger.ts
CHANGED
|
@@ -6,7 +6,7 @@ export default class Logger {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
log(...message: string[]): void {
|
|
9
|
-
//
|
|
9
|
+
// oxlint-disable-next-line eslint/no-console
|
|
10
10
|
console.log(...message)
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ export default class Logger {
|
|
|
15
15
|
return
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
//
|
|
18
|
+
// oxlint-disable-next-line eslint/no-console
|
|
19
19
|
console.log(...message)
|
|
20
20
|
}
|
|
21
21
|
}
|
package/src/utils/index.ts
CHANGED
|
@@ -3,25 +3,28 @@ import syncFs, { promises as fs } from 'node:fs'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { createInterface } from 'node:readline'
|
|
5
5
|
|
|
6
|
+
interface ExportedNames {
|
|
7
|
+
valueNames: string[]
|
|
8
|
+
typeNames: string[]
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
/**
|
|
7
12
|
* Extract exported symbol names from a ts-proto generated TypeScript file.
|
|
8
13
|
* Returns arrays of value exports and type-only exports separately.
|
|
9
14
|
* Names that exist as both value and type (e.g. interface + const with same name)
|
|
10
15
|
* are only included in valueNames to avoid duplicate identifier errors.
|
|
11
16
|
*/
|
|
12
|
-
function extractExportedNames(content: string):
|
|
17
|
+
function extractExportedNames(content: string): ExportedNames {
|
|
13
18
|
const valueSet = new Set<string>()
|
|
14
19
|
const typeSet = new Set<string>()
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (match[2]) {
|
|
22
|
-
|
|
23
|
-
} else if (match[4]) {
|
|
24
|
-
typeSet.add(match[4])
|
|
21
|
+
const exportRegex = /^export\s+(?:(?:const|let|var|function|enum|class)\s+(\w+)|(?:interface|type)\s+(\w+))/gm
|
|
22
|
+
|
|
23
|
+
for (const match of content.matchAll(exportRegex)) {
|
|
24
|
+
if (match[1]) {
|
|
25
|
+
valueSet.add(match[1])
|
|
26
|
+
} else if (match[2]) {
|
|
27
|
+
typeSet.add(match[2])
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
@@ -36,7 +39,6 @@ export default {
|
|
|
36
39
|
const exportedNames = new Set<string>()
|
|
37
40
|
|
|
38
41
|
const recursivePaths = async (realpath: string): Promise<string[]> => {
|
|
39
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
40
42
|
const items = await fs.readdir(realpath, { withFileTypes: true }) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
41
43
|
let paths: string[] = []
|
|
42
44
|
|
|
@@ -54,7 +56,6 @@ export default {
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
for (const recPaths of await recursivePaths(dir)) {
|
|
57
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
58
59
|
const stream = syncFs.createReadStream(recPaths) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
59
60
|
const rl = createInterface({
|
|
60
61
|
input: stream,
|
|
@@ -69,10 +70,8 @@ export default {
|
|
|
69
70
|
const protoFile = matchArr[1]
|
|
70
71
|
|
|
71
72
|
const protofilepath = path.resolve(protoRoot, protoFile)
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
if (syncFs.existsSync(protofilepath)) { // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
75
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
73
|
+
const exists = syncFs.existsSync(protofilepath) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
74
|
+
if (exists) {
|
|
76
75
|
const contents = syncFs.readFileSync(protofilepath) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
77
76
|
|
|
78
77
|
ownPackage = contents.includes('package ua.gov.diia')
|
|
@@ -94,7 +93,6 @@ export default {
|
|
|
94
93
|
|
|
95
94
|
if (ownPackage) {
|
|
96
95
|
// Read file and extract exported names to avoid re-export conflicts (TS2308)
|
|
97
|
-
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
|
98
96
|
const content = await fs.readFile(recPaths, 'utf8') // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
99
97
|
const { valueNames, typeNames } = extractExportedNames(content)
|
|
100
98
|
|
|
@@ -118,7 +116,6 @@ export default {
|
|
|
118
116
|
exportLines.push(parts.join('\n'))
|
|
119
117
|
}
|
|
120
118
|
} else {
|
|
121
|
-
// eslint-disable-next-line unicorn/prefer-string-replace-all
|
|
122
119
|
const namespace = fileNameWithPrefix.replace(/[/\\]/g, '_').replace(/[^\w$]/g, '_')
|
|
123
120
|
|
|
124
121
|
exportLines.push(`export * as ${namespace} from '${importPath}';`)
|
|
@@ -128,8 +125,7 @@ export default {
|
|
|
128
125
|
if (exportLines.length > 0) {
|
|
129
126
|
const indexFilePath = path.join(dir, 'index.ts')
|
|
130
127
|
|
|
131
|
-
// eslint
|
|
132
|
-
await fs.writeFile(indexFilePath, exportLines.join('\n\n') + '\n') // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
128
|
+
await fs.writeFile(indexFilePath, `${exportLines.join('\n\n')}\n`) // nosemgrep: eslint.detect-non-literal-fs-filename
|
|
133
129
|
}
|
|
134
130
|
},
|
|
135
131
|
}
|