-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
validations.ts
102 lines (87 loc) · 3.07 KB
/
validations.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { GluegunToolbox } from "gluegun"
import { prefix } from "./pretty"
// #region Error Guards
type IsError = (str: string) => boolean
type ErrorMessage = (str?: string) => string
type ErrorGuard = [IsError, ErrorMessage]
const isIgnite: ErrorGuard = [
(str) => str.toLowerCase() === "ignite",
(str) => `Hey...that's my name! Please name your project something other than '${str}'.`,
]
const isOnlyNumbers: ErrorGuard = [
(str) => /^\d+$/.test(str),
() => `Please use at least one non-numeric character for your project name`,
]
const isNotAlphaNumeric: ErrorGuard = [
(str) => !/^[a-z_][a-z0-9_-]+$/i.test(str),
() =>
`The project name can only contain alphanumeric characters and underscore, but must not begin with a number.`,
]
const guards: ErrorGuard[] = [isIgnite, isOnlyNumbers, isNotAlphaNumeric]
/**
* check if the value matches any of the error guards
* @returns error message from the first guard that matches, or `true` if no guards match
*/
const validate = (value: string): true | string => {
for (const [isError, errorMessage] of guards) {
if (isError(value)) {
return errorMessage(value)
}
}
return true
}
// #endregion
export async function validateProjectName(toolbox: GluegunToolbox): Promise<string> {
const { parameters, strings, print } = toolbox
const { isBlank } = strings
// grab the project name
let projectName: string = (parameters.first || "").toString()
// verify the project name is a thing
if (isBlank(projectName)) {
const projectNameResponse = await toolbox.prompt.ask(() => ({
name: "projectName",
type: "input",
message: "What do you want to call it?",
prefix,
validate,
}))
projectName = projectNameResponse.projectName
}
// warn if more than one argument is provided for <projectName>
if (parameters.second) {
print.info(`Info: You provided more than one argument for <projectName>. The first one (${projectName}) will be used and the rest are ignored.`) // prettier-ignore
}
const error = validate(projectName)
if (typeof error === "string") {
print.error(error)
process.exit(1)
}
return projectName
}
export function validateBundleIdentifier(
toolbox: GluegunToolbox,
bundleID: string | undefined,
): string | undefined {
const { print } = toolbox
// no bundle ID provided
if (bundleID === undefined) return undefined
const id = bundleID.split(".")
const validBundleID = /^([a-zA-Z]([a-zA-Z0-9_])*\.)+[a-zA-Z]([a-zA-Z0-9_])*$/u
if (id.length < 2) {
print.error(
'Invalid Bundle Identifier. Add something like "com.travelapp" or "com.junedomingo.travelapp"',
)
process.exit(1)
}
if (!validBundleID.test(bundleID)) {
print.error(
"Invalid Bundle Identifier. It must have at least two segments (one or more dots). Each segment must start with a letter. All characters must be alphanumeric or an underscore [a-zA-Z0-9_]",
)
process.exit(1)
}
return bundleID
}
export type ValidationsExports = {
validateProjectName: typeof validateProjectName
validateBundleIdentifier: typeof validateBundleIdentifier
}