Passed
Push — master ( 3dfca3...87dc5a )
by Roy
01:33
created

OSPaths.ts ➔ Adapt   F

Complexity

Conditions 16

Size

Total Lines 84
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 68
dl 0
loc 84
rs 2.4
c 0
b 0
f 0
cc 16

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like OSPaths.ts ➔ Adapt often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
// # spell-checker:ignore AllUsersProfile HomeDrive HomePath LocalAppData UserProfile WinDir falsey
2
3
import { Platform } from '../platform-adapters/_base.js';
4
5
type OSPathsOptions = {
6
	readonly name: string;
7
};
8
9
/** Determine common OS/platform paths (home, temp, ...) */
10
type OSPaths = {
11
	/** @constructor Create an `OSPaths` object. */
12
	(): OSPaths;
13
	/** @constructor Create an `OSPaths` object. */
14
	new (): OSPaths;
15
	/* eslint-disable functional/no-method-signature */
16
	/** Returns the path string of the user's home directory (or `undefined` if the user's home directory is not resolvable). */
17
	home(): string | undefined;
18
	/** Returns the path string of the system's default directory for temporary files. */
19
	temp(): string;
20
	/** Mock ~ returns the name supplied in OSPathOptions. */
21
	mock(options: OSPathsOptions | undefined): string;
22
	/* eslint-enable functional/no-method-signature */
23
};
24
25
function isEmpty(s: string | null | undefined): boolean {
26
	return !s; // reminder: JS "falsey" == [undefined, null, NaN, 0, '', false]
27
}
28
29
function Adapt(adapter_: Platform.Adapter): { readonly OSPaths: OSPaths } {
30
	const { env, os, path } = adapter_;
31
32
	const isWinOS = /^win/i.test(adapter_.process.platform);
33
34
	function normalizePath(path_: string | undefined): string | undefined {
35
		return path_ ? adapter_.path.normalize(adapter_.path.join(path_, '.')) : void 0;
36
	}
37
38
	function home() {
39
		const posix = () =>
40
			normalizePath((typeof os.homedir === 'function' ? os.homedir() : void 0) || env.get('HOME'));
41
42
		const windows = () => {
43
			const priorityList = [
44
				typeof os.homedir === 'function' ? os.homedir() : void 0,
45
				env.get('USERPROFILE'),
46
				env.get('HOME'),
47
				env.get('HOMEDRIVE') || env.get('HOMEPATH')
48
					? path.join(env.get('HOMEDRIVE') || '', env.get('HOMEPATH') || '')
49
					: void 0,
50
			];
51
			return normalizePath(priorityList.find((v) => !isEmpty(v)));
52
		};
53
54
		return isWinOS ? windows() : posix();
55
	}
56
57
	function temp() {
58
		function joinPathToBase(base: string | undefined, segments: readonly string[]) {
59
			return base ? path.join(base, ...segments) : void 0;
60
		}
61
62
		function posix() {
63
			const fallback = '/tmp';
64
			const priorityList = [
65
				typeof os.tmpdir === 'function' ? os.tmpdir() : void 0,
66
				env.get('TMPDIR'),
67
				env.get('TEMP'),
68
				env.get('TMP'),
69
			];
70
			return normalizePath(priorityList.find((v) => !isEmpty(v))) || fallback;
71
		}
72
73
		function windows() {
74
			const fallback = 'C:\\Temp';
75
			const priorityListLazy = [
76
				os.tmpdir,
77
				() => env.get('TEMP'),
78
				() => env.get('TMP'),
79
				() => joinPathToBase(env.get('LOCALAPPDATA'), ['Temp']),
80
				() => joinPathToBase(home(), ['AppData', 'Local', 'Temp']),
81
				() => joinPathToBase(env.get('ALLUSERSPROFILE'), ['Temp']),
82
				() => joinPathToBase(env.get('SystemRoot'), ['Temp']),
83
				() => joinPathToBase(env.get('windir'), ['Temp']),
84
				() => joinPathToBase(env.get('SystemDrive'), ['\\', 'Temp']),
85
			];
86
			const v = priorityListLazy.find((v) => v && !isEmpty(v()));
87
			return (v && normalizePath(v())) || fallback;
88
		}
89
90
		return isWinOS ? windows() : posix();
91
	}
92
93
	// eslint-disable-next-line functional/no-class
94
	class OSPaths_ {
95
		constructor() {
96
			function OSPaths(): OSPaths {
97
				return new OSPaths_() as OSPaths;
98
			}
99
100
			OSPaths.home = home;
101
			OSPaths.temp = temp;
102
103
			OSPaths.mock = function name(options: OSPathsOptions = { name: 'default_name' }) {
104
				return options.name;
105
			};
106
107
			return OSPaths;
108
		}
109
	}
110
111
	return { OSPaths: new OSPaths_() as OSPaths };
112
}
113
114
export type { OSPaths, OSPathsOptions };
115
export { Adapt };
116