platformdirs 4.3.6 → 4.3.8-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/api.js ADDED
@@ -0,0 +1,444 @@
1
+ /**
2
+ * Base API.
3
+ * @module
4
+ */
5
+
6
+ import * as fs from "node:fs";
7
+ import * as path from "node:path";
8
+
9
+ /**
10
+ * Abstract base class for platform directories.
11
+ * @abstract
12
+ */
13
+ export class PlatformDirsABC {
14
+ /**
15
+ * The name of the application.
16
+ * @type {string|undefined}
17
+ */
18
+ appname;
19
+ /**
20
+ * The name of the app author or distributing body for this application.
21
+ *
22
+ * Typically it is the owning company name. Defaults to `appname`. You may pass `false` to disable it.
23
+ * @type {string|false|undefined}
24
+ */
25
+ appauthor;
26
+ /**
27
+ * An optional version path element to append to the path.
28
+ *
29
+ * You might want to use this if you want multiple versions of your app to be able to run independently. If used, this would typically be `<major>.<minor>`.
30
+ * @type {string|undefined}
31
+ */
32
+ version;
33
+ /**
34
+ * Whether to use the roaming appdata directory on Windows.
35
+ *
36
+ * That means that for users on a Windows network setup for roaming profiles, this user data will be synced on login (see [here](https://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx)).
37
+ * @type {boolean}
38
+ */
39
+ roaming;
40
+ /**
41
+ * An optional parameter which indicates that the entire list of data dirs should be returned.
42
+ *
43
+ * By default, the first item would only be returned.
44
+ * @type {boolean}
45
+ */
46
+ multipath;
47
+ /**
48
+ * A flag to indicating to use opinionated values.
49
+ * @type {boolean}
50
+ */
51
+ opinion;
52
+ /**
53
+ * Optionally create the directory (and any missing parents) upon access if
54
+ * it does not exist.
55
+ *
56
+ * By default, no directories are created.
57
+ *
58
+ * ⚠️ Since the getters (`dirs.userDataDir`, etc.) are synchronous, the
59
+ * directory creation will use `fs.mkdirSync()` which **is a blocking
60
+ * synchronous operation** to ensure that the returned path does indeed
61
+ * exist before returning the path to the caller. This is for convenience.
62
+ * If you require non-blocking async operation you should set this to
63
+ * `false` and use `fs.mkdir()` or `fsPromises.mkdir()` yourself.
64
+ * @type {boolean}
65
+ */
66
+ ensureExists;
67
+ /**
68
+ * Create a new platform directory.
69
+ * @param {string} [appname] - See `appname`
70
+ * @param {string|false} [appauthor] - See `appauthor`
71
+ * @param {string} [version] - See `version`
72
+ * @param {boolean} [roaming=false] - See `roaming`
73
+ * @param {boolean} [multipath=false] - See `multipath`
74
+ * @param {boolean} [opinion=true] - See `opinion`
75
+ * @param {boolean} [ensureExists=false] - See `ensureExists`
76
+ */
77
+ constructor(
78
+ appname,
79
+ appauthor,
80
+ version,
81
+ roaming = false,
82
+ multipath = false,
83
+ opinion = true,
84
+ ensureExists = false,
85
+ ) {
86
+ this.appname = appname;
87
+ this.appauthor = appauthor;
88
+ this.version = version;
89
+ this.roaming = roaming;
90
+ this.multipath = multipath;
91
+ this.opinion = opinion;
92
+ this.ensureExists = ensureExists;
93
+ }
94
+
95
+ /**
96
+ * @param {string[]} base
97
+ * @return {string}
98
+ * @protected @ignore @internal
99
+ */
100
+ _appendAppNameAndVersion(...base) {
101
+ const params = base.slice(1);
102
+ if (this.appname) {
103
+ params.push(this.appname);
104
+ if (this.version) {
105
+ params.push(this.version);
106
+ }
107
+ }
108
+ const path2 = path.join(base[0], ...params);
109
+ this._optionallyCreateDirectory(path2);
110
+ return path2;
111
+ }
112
+
113
+ /**
114
+ * @param {string} dir
115
+ * @protected @ignore @internal
116
+ */
117
+ _optionallyCreateDirectory(dir) {
118
+ if (this.ensureExists) {
119
+ fs.mkdirSync(dir, { recursive: true });
120
+ }
121
+ }
122
+
123
+ /**
124
+ * @param {string} directory
125
+ * @return {string}
126
+ * @protected @ignore @internal
127
+ */
128
+ _firstItemAsPathIfMultipath(directory) {
129
+ if (this.multipath) {
130
+ return directory.split(path.delimiter)[0];
131
+ }
132
+ return directory;
133
+ }
134
+
135
+ /**
136
+ * @return {string} data directory tied to the user
137
+ * @abstract
138
+ */
139
+ get userDataDir() {
140
+ throw new Error("abstract");
141
+ }
142
+
143
+ /**
144
+ * @return {string} data directory shared by users
145
+ * @abstract
146
+ */
147
+ get siteDataDir() {
148
+ throw new Error("abstract");
149
+ }
150
+
151
+ /**
152
+ * @return {string} config directory tied to the user
153
+ * @abstract
154
+ */
155
+ get userConfigDir() {
156
+ throw new Error("abstract");
157
+ }
158
+
159
+ /**
160
+ * @return {string} config directory shared by users
161
+ * @abstract
162
+ */
163
+ get siteConfigDir() {
164
+ throw new Error("abstract");
165
+ }
166
+
167
+ /**
168
+ * @return {string} cache directory tied to the user
169
+ * @abstract
170
+ */
171
+ get userCacheDir() {
172
+ throw new Error("abstract");
173
+ }
174
+
175
+ /**
176
+ * @return {string} cache directory shared by users
177
+ * @abstract
178
+ */
179
+ get siteCacheDir() {
180
+ throw new Error("abstract");
181
+ }
182
+
183
+ /**
184
+ * @return {string} state directory tied to the user
185
+ * @abstract
186
+ */
187
+ get userStateDir() {
188
+ throw new Error("abstract");
189
+ }
190
+
191
+ /**
192
+ * @return {string} log directory tied to the user
193
+ * @abstract
194
+ */
195
+ get userLogDir() {
196
+ throw new Error("abstract");
197
+ }
198
+
199
+ /**
200
+ * @return {string} documents directory tied to the user
201
+ * @abstract
202
+ */
203
+ get userDocumentsDir() {
204
+ throw new Error("abstract");
205
+ }
206
+
207
+ /**
208
+ * @return {string} downloads directory tied to the user
209
+ * @abstract
210
+ */
211
+ get userDownloadsDir() {
212
+ throw new Error("abstract");
213
+ }
214
+
215
+ /**
216
+ * @return {string} pictures directory tied to the user
217
+ * @abstract
218
+ */
219
+ get userPicturesDir() {
220
+ throw new Error("abstract");
221
+ }
222
+
223
+ /**
224
+ * @return {string} videos directory tied to the user
225
+ * @abstract
226
+ */
227
+ get userVideosDir() {
228
+ throw new Error("abstract");
229
+ }
230
+
231
+ /**
232
+ * @return {string} music directory tied to the user
233
+ * @abstract
234
+ */
235
+ get userMusicDir() {
236
+ throw new Error("abstract");
237
+ }
238
+
239
+ /**
240
+ * @return {string} desktop directory tied to the user
241
+ * @abstract
242
+ */
243
+ get userDesktopDir() {
244
+ throw new Error("abstract");
245
+ }
246
+
247
+ /**
248
+ * @return {string} runtime directory tied to the user
249
+ * @abstract
250
+ */
251
+ get userRuntimeDir() {
252
+ throw new Error("abstract");
253
+ }
254
+
255
+ /**
256
+ * @return {string} runtime directory shared by users
257
+ * @abstract
258
+ */
259
+ get siteRuntimeDir() {
260
+ throw new Error("abstract");
261
+ }
262
+
263
+ /**
264
+ * @return {string} data path tied to the user
265
+ */
266
+ get userDataPath() {
267
+ return this.userDataDir;
268
+ }
269
+
270
+ /**
271
+ * @return {string} data path shared by users
272
+ */
273
+ get siteDataPath() {
274
+ return this.siteDataDir;
275
+ }
276
+
277
+ /**
278
+ * @return {string} config path tied to the user
279
+ */
280
+ get userConfigPath() {
281
+ return this.userConfigDir;
282
+ }
283
+
284
+ /**
285
+ * @return {string} config path shared by users
286
+ */
287
+ get siteConfigPath() {
288
+ return this.siteConfigDir;
289
+ }
290
+
291
+ /**
292
+ * @return {string} cache path tied to the user
293
+ */
294
+ get userCachePath() {
295
+ return this.userCacheDir;
296
+ }
297
+
298
+ /**
299
+ * @return {string} cache path shared by users
300
+ */
301
+ get siteCachePath() {
302
+ return this.siteCacheDir;
303
+ }
304
+
305
+ /**
306
+ * @return {string} state path tied to the user
307
+ */
308
+ get userStatePath() {
309
+ return this.userStateDir;
310
+ }
311
+
312
+ /**
313
+ * @return {string} log path tied to the user
314
+ */
315
+ get userLogPath() {
316
+ return this.userLogDir;
317
+ }
318
+
319
+ /**
320
+ * @return {string} documents path tied to the user
321
+ */
322
+ get userDocumentsPath() {
323
+ return this.userDocumentsDir;
324
+ }
325
+
326
+ /**
327
+ * @return {string} downloads path tied to the user
328
+ */
329
+ get userDownloadsPath() {
330
+ return this.userDownloadsDir;
331
+ }
332
+
333
+ /**
334
+ * @return {string} pictures path tied to the user
335
+ */
336
+ get userPicturesPath() {
337
+ return this.userPicturesDir;
338
+ }
339
+
340
+ /**
341
+ * @return {string} videos path tied to the user
342
+ */
343
+ get userVideosPath() {
344
+ return this.userVideosDir;
345
+ }
346
+
347
+ /**
348
+ * @return {string} music path tied to the user
349
+ */
350
+ get userMusicPath() {
351
+ return this.userMusicDir;
352
+ }
353
+
354
+ /**
355
+ * @return {string} desktop path tied to the user
356
+ */
357
+ get userDesktopPath() {
358
+ return this.userDesktopDir;
359
+ }
360
+
361
+ /**
362
+ * @return {string} runtime path tied to the user
363
+ */
364
+ get userRuntimePath() {
365
+ return this.userRuntimeDir;
366
+ }
367
+
368
+ /**
369
+ * @return {string} runtime path shared by users
370
+ */
371
+ get siteRuntimePath() {
372
+ return this.siteRuntimeDir;
373
+ }
374
+
375
+ // https://github.com/microsoft/TypeScript/issues/23857
376
+
377
+ /**
378
+ * @yields all user and site configuration directories
379
+ * @returns {Generator<string>}
380
+ */
381
+ *iterConfigDirs() {
382
+ yield this.userConfigDir;
383
+ yield this.siteConfigDir;
384
+ }
385
+
386
+ /**
387
+ * @yields all user and site data directories
388
+ * @returns {Generator<string>}
389
+ */
390
+ *iterDataDirs() {
391
+ yield this.userDataDir;
392
+ yield this.siteDataDir;
393
+ }
394
+
395
+ /**
396
+ * @yields all user and site cache directories
397
+ * @returns {Generator<string>}
398
+ */
399
+ *iterCacheDirs() {
400
+ yield this.userCacheDir;
401
+ yield this.siteCacheDir;
402
+ }
403
+
404
+ /**
405
+ * @yields all user and site runtime directories
406
+ * @returns {Generator<string>}
407
+ */
408
+ *iterRuntimeDirs() {
409
+ yield this.userRuntimeDir;
410
+ yield this.siteRuntimeDir;
411
+ }
412
+
413
+ /**
414
+ * @yields all user and site state directories
415
+ * @returns {Generator<string>}
416
+ */
417
+ *iterConfigPaths() {
418
+ yield* this.iterConfigDirs();
419
+ }
420
+
421
+ /**
422
+ * @yields all user and site data directories
423
+ * @returns {Generator<string>}
424
+ */
425
+ *iterDataPaths() {
426
+ yield* this.iterDataDirs();
427
+ }
428
+
429
+ /**
430
+ * @yields all user and site cache directories
431
+ * @returns {Generator<string>}
432
+ */
433
+ *iterCachePaths() {
434
+ yield* this.iterCacheDirs();
435
+ }
436
+
437
+ /**
438
+ * @yields all user and site runtime directories
439
+ * @returns {Generator<string>}
440
+ */
441
+ *iterRuntimePaths() {
442
+ yield* this.iterRuntimeDirs();
443
+ }
444
+ }
@@ -0,0 +1,73 @@
1
+ // Stub of to https://docs.python.org/3/library/configparser.html.
2
+ // Must parse files like https://github.com/search?q=path%3Auser-dirs.dirs&type=code.
3
+
4
+ /*
5
+ # comment
6
+ [section]
7
+ key = value
8
+ */
9
+
10
+ /*
11
+ # skeleton ~/.config/user-dirs.dirs
12
+ XDG_DESKTOP_DIR="$HOME/.local/share/Desktop"
13
+ XDG_DOCUMENTS_DIR="$HOME/Dropbox"
14
+ XDG_DOWNLOAD_DIR="$HOME/Downloads"
15
+ XDG_MUSIC_DIR="$HOME/Music"
16
+ XDG_PICTURES_DIR="$HOME/Pictures"
17
+ */
18
+
19
+ export class ConfigParser {
20
+ /**
21
+ * @type {Record<string, Record<string, string>> | null}
22
+ */
23
+ data = null;
24
+
25
+ /**
26
+ * @param {string} input
27
+ */
28
+ readString(input) {
29
+ /** @type {Record<string, Record<string, string>>} */
30
+ const data = {};
31
+ let sectionName = "";
32
+ for (const line of input.split(/\r?\n/g)) {
33
+ if (line.startsWith("#")) {
34
+ continue;
35
+ }
36
+
37
+ if (line.trim() === "") {
38
+ continue;
39
+ }
40
+
41
+ const match = line.match(/^\[(.*)\]$/);
42
+ if (match != null) {
43
+ sectionName = match[1];
44
+ continue;
45
+ }
46
+
47
+ data[sectionName] ??= {};
48
+ const match2 = line.match(/^([^=]+)=(.*)$/);
49
+ if (match2 == null) {
50
+ continue;
51
+ }
52
+
53
+ const key = match2[1].trim();
54
+ const value = match2[2].trim();
55
+ data[sectionName][key] = value;
56
+ }
57
+ this.data = data;
58
+ }
59
+
60
+ /**
61
+ * @param {string} key
62
+ * @return {Record<string, string> | undefined}
63
+ */
64
+ get(key) {
65
+ if (this.data === null) {
66
+ return undefined;
67
+ }
68
+ if (Object.hasOwn(this.data, key)) {
69
+ return this.data[key];
70
+ }
71
+ return undefined;
72
+ }
73
+ }