@platformatic/foundation 3.0.0-alpha.2
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/LICENSE +201 -0
- package/NOTICE +13 -0
- package/eslint.config.js +64 -0
- package/index.d.ts +248 -0
- package/index.js +12 -0
- package/lib/cli.js +231 -0
- package/lib/configuration.js +525 -0
- package/lib/errors.js +58 -0
- package/lib/execution.js +13 -0
- package/lib/file-system.js +188 -0
- package/lib/logger.js +180 -0
- package/lib/module.js +175 -0
- package/lib/node.js +24 -0
- package/lib/object.js +35 -0
- package/lib/schema.js +1189 -0
- package/lib/string.js +95 -0
- package/package.json +53 -0
package/lib/cli.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { bgGreen, black, bold, green, isColorSupported } from 'colorette'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { parseArgs as nodeParseArgs } from 'node:util'
|
|
4
|
+
import { pino } from 'pino'
|
|
5
|
+
import pinoPretty from 'pino-pretty'
|
|
6
|
+
import { findConfigurationFileRecursive, loadConfigurationModule, saveConfigurationFile } from './configuration.js'
|
|
7
|
+
import { hasJavascriptFiles } from './file-system.js'
|
|
8
|
+
import { detectApplicationType, getPlatformaticVersion } from './module.js'
|
|
9
|
+
|
|
10
|
+
/* c8 ignore next 3 - else branches */
|
|
11
|
+
let verbose = false
|
|
12
|
+
let executableId = ''
|
|
13
|
+
let executableName = ''
|
|
14
|
+
|
|
15
|
+
export function isVerbose () {
|
|
16
|
+
return verbose
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getExecutableId () {
|
|
20
|
+
return executableId
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getExecutableName () {
|
|
24
|
+
return executableName
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function setVerbose (value) {
|
|
28
|
+
verbose = value
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function setExecutableId (id) {
|
|
32
|
+
executableId = id
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function setExecutableName (name) {
|
|
36
|
+
executableName = name
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function logo (color = true) {
|
|
40
|
+
/* c8 ignore next - else */
|
|
41
|
+
const executableName = color && isColorSupported ? bold(getExecutableName()) : getExecutableName()
|
|
42
|
+
const str = `
|
|
43
|
+
|
|
44
|
+
//////
|
|
45
|
+
/////////////
|
|
46
|
+
/////// ///////
|
|
47
|
+
/////// ///////
|
|
48
|
+
/////// ///////
|
|
49
|
+
//// ////
|
|
50
|
+
&&&& //// //// &&&&
|
|
51
|
+
&&&&&&& //// //// &&&&&&&
|
|
52
|
+
&&&&&&& //// //// &&&&&&&
|
|
53
|
+
&&&& //// //// &&&&&&&
|
|
54
|
+
&&&& //// //// &&&& &&
|
|
55
|
+
&&&& //// //// &&& &&&&&&
|
|
56
|
+
&&&& //// //// &&& &&&&&&
|
|
57
|
+
&&&& ///// ///// &&& &&&&
|
|
58
|
+
&&&& /////// /////// &&& &&&&
|
|
59
|
+
&&&& ////// /////// &&& &&&&&&&
|
|
60
|
+
&&&& //// ///////// //////// &&& &&&&&&
|
|
61
|
+
&&&& //// /// //////////// &&&& &&& &&&
|
|
62
|
+
&&&&&&& //// /// ///// &&&& &&&&
|
|
63
|
+
&&&&&&& //// &&& &&&&& &&&&&&&
|
|
64
|
+
&&& //// &&&& &&&&&&& &&&&&&&
|
|
65
|
+
//// &&& &&&& &&&&&&&&&&
|
|
66
|
+
//// &&& &&&& &&&&
|
|
67
|
+
// &&&&& &&&&
|
|
68
|
+
&&&&&&& &&&&&&
|
|
69
|
+
&&&&&&&&&&&&&
|
|
70
|
+
&&&&&&
|
|
71
|
+
|
|
72
|
+
Welcome to ${executableName}!
|
|
73
|
+
`
|
|
74
|
+
|
|
75
|
+
/* c8 ignore next - else */
|
|
76
|
+
return color && isColorSupported ? str.replace(/\//g, s => green(s)) : str
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function createCliLogger (level) {
|
|
80
|
+
return pino(
|
|
81
|
+
{
|
|
82
|
+
level,
|
|
83
|
+
customLevels: {
|
|
84
|
+
done: 35
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
pinoPretty({
|
|
88
|
+
colorize: process.env.NO_COLOR !== 'true',
|
|
89
|
+
customPrettifiers: {
|
|
90
|
+
level (logLevel, _u1, _u2, { label, labelColorized }) {
|
|
91
|
+
/* c8 ignore next - else */
|
|
92
|
+
return logLevel === 35 ? bgGreen(black(label)) : labelColorized
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
sync: true
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function logFatalError (logger, ...args) {
|
|
101
|
+
process.exitCode = 1
|
|
102
|
+
logger.fatal(...args)
|
|
103
|
+
return false
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function parseArgs (args, options, stopAtFirstPositional = true, strict = true) {
|
|
107
|
+
let unparsed = []
|
|
108
|
+
|
|
109
|
+
if (stopAtFirstPositional) {
|
|
110
|
+
// Parse a first time to get tokens and see where the first positional, if any, is
|
|
111
|
+
const { tokens } = nodeParseArgs({
|
|
112
|
+
args,
|
|
113
|
+
options,
|
|
114
|
+
allowPositionals: true,
|
|
115
|
+
allowNegative: true,
|
|
116
|
+
strict: false,
|
|
117
|
+
tokens: true
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const firstPositional = tokens.find(t => t.kind === 'positional')
|
|
121
|
+
|
|
122
|
+
if (firstPositional) {
|
|
123
|
+
unparsed = args.slice(firstPositional.index)
|
|
124
|
+
args = args.slice(0, firstPositional.index)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const { tokens, values, positionals } = nodeParseArgs({
|
|
129
|
+
args,
|
|
130
|
+
options,
|
|
131
|
+
allowPositionals: true,
|
|
132
|
+
allowNegative: true,
|
|
133
|
+
strict,
|
|
134
|
+
tokens: true
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
values,
|
|
139
|
+
positionals,
|
|
140
|
+
unparsed,
|
|
141
|
+
tokens
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function getRoot (positionals) {
|
|
146
|
+
let root = process.cwd()
|
|
147
|
+
|
|
148
|
+
if (positionals?.[0]) {
|
|
149
|
+
root = resolve(root, positionals[0])
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return root
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function serviceToEnvVariable (service) {
|
|
156
|
+
return `PLT_SERVICE_${service.toUpperCase().replaceAll(/[^A-Z0-9_]/g, '_')}_PATH`
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function findRuntimeConfigurationFile (
|
|
160
|
+
logger,
|
|
161
|
+
root,
|
|
162
|
+
configurationFile,
|
|
163
|
+
fallback = true,
|
|
164
|
+
throwOnError = true,
|
|
165
|
+
verifyPackages = true
|
|
166
|
+
) {
|
|
167
|
+
let configFile = await findConfigurationFileRecursive(root, configurationFile, '@platformatic/runtime')
|
|
168
|
+
|
|
169
|
+
// If a runtime was not found, search for service file that we wrap in a runtime
|
|
170
|
+
if (!configFile && !configurationFile) {
|
|
171
|
+
configFile = await findConfigurationFileRecursive(root, configurationFile)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// No configuration yet, try to create a new one
|
|
175
|
+
if (!configFile) {
|
|
176
|
+
if (fallback) {
|
|
177
|
+
configurationFile = await fallbackToTemporaryConfigFile(logger, root, verifyPackages)
|
|
178
|
+
|
|
179
|
+
/* c8 ignore next - else */
|
|
180
|
+
if (configurationFile || configurationFile === false) {
|
|
181
|
+
return configurationFile
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (throwOnError) {
|
|
186
|
+
return logFatalError(
|
|
187
|
+
logger,
|
|
188
|
+
`Cannot find a supported ${getExecutableName()} configuration file (like ${bold('watt.json')}, a ${bold('wattpm.json')} or a ${bold(
|
|
189
|
+
'platformatic.json'
|
|
190
|
+
)}) in ${bold(resolve(root))}.`
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return configFile
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function fallbackToTemporaryConfigFile (logger, root, verifyPackages) {
|
|
199
|
+
const hasJsFiles = await hasJavascriptFiles(root)
|
|
200
|
+
|
|
201
|
+
if (!hasJsFiles) {
|
|
202
|
+
// Do not return false here, that is reserved below to signal that a file was created but no module was available.
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const { name, label } = await detectApplicationType(root)
|
|
207
|
+
|
|
208
|
+
/* c8 ignore next - else */
|
|
209
|
+
const autodetectDescription = name === '@platformatic/node' ? 'is a generic Node.js application' : `is using ${label}`
|
|
210
|
+
|
|
211
|
+
logger.warn(
|
|
212
|
+
`We have auto-detected that the current folder ${bold(autodetectDescription)} so we have created a ${bold('watt.json')} file for you automatically.`
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
const schema = `https://schemas.platformatic.dev/${name}/${await getPlatformaticVersion()}.json?autogenerated=true`
|
|
216
|
+
const configurationFile = resolve(root, 'watt.json')
|
|
217
|
+
await saveConfigurationFile(configurationFile, { $schema: schema })
|
|
218
|
+
|
|
219
|
+
// Try to load the module, if it is missing, we will throw an error
|
|
220
|
+
if (verifyPackages) {
|
|
221
|
+
try {
|
|
222
|
+
await loadConfigurationModule(root, { $schema: schema })
|
|
223
|
+
/* c8 ignore next 4 - covered */
|
|
224
|
+
} catch (error) {
|
|
225
|
+
logFatalError(logger, `Cannot load module ${bold(name)}. Please add it to your package.json and try again.`)
|
|
226
|
+
return false
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return configurationFile
|
|
231
|
+
}
|