generated from JS-DevTools/template-node-typescript
-
Notifications
You must be signed in to change notification settings - Fork 78
/
Copy pathnormalize-options.ts
130 lines (110 loc) · 3.5 KB
/
normalize-options.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import os from "node:os";
import * as errors from "./errors.js";
import type { PackageManifest } from "./read-manifest.js";
import {
ACCESS_PUBLIC,
ACCESS_RESTRICTED,
STRATEGY_UPGRADE,
STRATEGY_ALL,
type Access,
type Strategy,
type Options,
type Logger,
} from "./options.js";
const REGISTRY_NPM = "https://registry.npmjs.org/";
export const TAG_LATEST = "latest";
/** Normalized and sanitized auth, publish, and runtime configurations. */
export interface NormalizedOptions {
registry: URL;
token: string;
tag: ConfigValue<string>;
access: ConfigValue<Access | undefined>;
provenance: ConfigValue<boolean>;
ignoreScripts: ConfigValue<boolean>;
dryRun: ConfigValue<boolean>;
strategy: ConfigValue<Strategy>;
logger: Logger | undefined;
temporaryDirectory: string;
}
/** A config value, and whether that value differs from default. */
export interface ConfigValue<TValue> {
value: TValue;
isDefault: boolean;
}
/**
* Normalizes and sanitizes options, and fills-in any default values.
*
* @param manifest Package metadata from package.json.
* @param options User-input options.
* @returns Validated auth and publish configuration.
*/
export function normalizeOptions(
manifest: PackageManifest,
options: Options
): NormalizedOptions {
const defaultTag = manifest.publishConfig?.tag ?? TAG_LATEST;
const defaultRegistry = manifest.publishConfig?.registry ?? REGISTRY_NPM;
const defaultAccess =
manifest.publishConfig?.access ??
(manifest.scope === undefined ? ACCESS_PUBLIC : undefined);
const defaultProvenance = manifest.publishConfig?.provenance ?? false;
return {
token: validateToken(options.token),
registry: validateRegistry(options.registry ?? defaultRegistry),
tag: setValue(options.tag, defaultTag, validateTag),
access: setValue(options.access, defaultAccess, validateAccess),
provenance: setValue(options.provenance, defaultProvenance, Boolean),
ignoreScripts: setValue(options.ignoreScripts, true, Boolean),
dryRun: setValue(options.dryRun, false, Boolean),
strategy: setValue(options.strategy, STRATEGY_ALL, validateStrategy),
logger: options.logger,
temporaryDirectory: options.temporaryDirectory ?? os.tmpdir(),
};
}
const setValue = <TValue>(
value: unknown,
defaultValue: unknown,
validate: (value: unknown) => TValue
): ConfigValue<TValue> => ({
value: validate(value ?? defaultValue),
isDefault: value === undefined,
});
const validateToken = (value: unknown): string => {
if (typeof value === "string" && value.length > 0) {
return value;
}
throw new errors.InvalidTokenError();
};
const validateRegistry = (value: unknown): URL => {
try {
return new URL(value as string | URL);
} catch {
throw new errors.InvalidRegistryUrlError(value);
}
};
const validateTag = (value: unknown): string => {
if (typeof value === "string") {
const trimmedValue = value.trim();
const encodedValue = encodeURIComponent(trimmedValue);
if (trimmedValue.length > 0 && trimmedValue === encodedValue) {
return value;
}
}
throw new errors.InvalidTagError(value);
};
const validateAccess = (value: unknown): Access | undefined => {
if (
value === undefined ||
value === ACCESS_PUBLIC ||
value === ACCESS_RESTRICTED
) {
return value;
}
throw new errors.InvalidAccessError(value);
};
const validateStrategy = (value: unknown): Strategy => {
if (value === STRATEGY_ALL || value === STRATEGY_UPGRADE) {
return value;
}
throw new errors.InvalidStrategyError(value);
};