]> git.wincent.com - wincent.git/blob - src/path.ts
refactor(fig): set up path alias for "fig" -> "src"
[wincent.git] / src / path.ts
1 import {homedir} from 'os';
2 import {basename, dirname, join, normalize, relative, resolve} from 'path';
3
4 import Context from './Fig/Context.js';
5 import root from './Fig/root.js';
6
7 const inspect = Symbol.for('nodejs.util.inspect.custom');
8
9 // TODO: export path module wrappers as well, then I can just use it as a
10 // drop-in replacement
11
12 export type Path = string & {
13     basename: Path;
14     dirname: Path;
15     expand: Path;
16     join: (...components: Array<string>) => Path;
17     resolve: Path;
18     simplify: Path;
19     strip: (extension?: string) => Path;
20
21     // Makes sure value as printed by `console.log()` looks like a string.
22     [inspect]: () => string;
23 };
24
25 interface path {
26     (string: string): Path;
27
28     aspect: Path;
29     home: Path;
30     root: Path;
31 }
32
33 function path(string: string): Path {
34     // Unwrap (possible) Path string-like back to primitive string.
35     string = string.toString();
36
37     return Object.defineProperties(new String(string), {
38         basename: {
39             get() {
40                 return path(basename(string));
41             },
42         },
43
44         dirname: {
45             get() {
46                 return path(dirname(string));
47             },
48         },
49
50         expand: {
51             get() {
52                 if (string.startsWith('~/')) {
53                     return path(join(homedir(), string.slice(2)));
54                 } else {
55                     return path(string);
56                 }
57             },
58         },
59
60         join: {
61             value: (...components: Array<string>) => {
62                 return path(
63                     normalize(
64                         join(string, ...components.map((c) => c.toString()))
65                     )
66                 );
67             },
68         },
69
70         resolve: {
71             get() {
72                 if (string.startsWith('~/')) {
73                     return path(normalize(join(homedir(), string.slice(2))));
74                 } else {
75                     return path(resolve(string));
76                 }
77             },
78         },
79
80         simplify: {
81             get() {
82                 const home = homedir();
83
84                 if (string.startsWith(home)) {
85                     return path(join('~', string.slice(home.length)));
86                 } else {
87                     return path(relative('', string));
88                 }
89             },
90         },
91
92         /**
93          * Strips off ".ext" identified by `extension`, if present.
94          */
95         strip: {
96             value: (extension?: string) => {
97                 return path(join(dirname(string), basename(string, extension)));
98             },
99         },
100
101         [inspect]: {
102             value: () => string,
103         },
104     });
105 }
106
107 Object.defineProperty(path, 'aspect', {
108     get() {
109         return path(root).join('aspects', Context.currentAspect);
110     },
111 });
112
113 export default Object.assign(path, {
114     home: path('~'),
115
116     root: path(root),
117 }) as path;