forked from JS-DevTools/npm-publish
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnormalize-options.ts
125 lines (106 loc) · 3.35 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
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" && value.length > 0) {
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);
};