1
- # path-master
2
-
3
1
[ ![ JSR] ( https://jsr.io/badges/@midzdotdev/path-master )] ( https://jsr.io/@midzdotdev/path-master )
4
2
[ ![ Release Workflow] ( https://github.com/midzdotdev/path-master/actions/workflows/release.yml/badge.svg )] ( https://github.com/midzdotdev/path-master/actions/workflows/release.yml )
5
3
@@ -10,21 +8,94 @@ You can think of `path-master` as providing structure to files in the same way t
10
8
Path Master provides a whole host of benefits:
11
9
12
10
- 🏡 ** Centralised:** a single source of truth for defining paths
13
- - 🧬 ** Consistent:** standardises your path generation
14
- - ✨ ** Type-safe:** parameters are typed, and path types are inferred
15
11
- 📊 ** Parameterised:** paths are as dynamic as you need
12
+ - ✨ ** Type-safe:** parameters are typed, and path types are inferred
16
13
- 📈 ** Incremental:** model a complete file structure or just parts of it
14
+ - 🧬 ** Consistent:** standardises your path generation
17
15
18
16
> This library does not modify any filesystem directly,
19
17
> it's solely for modelling and generating paths.
20
18
21
- The applications for this are endless, but commonly useful with :
19
+ It can be used anywhere paths are used, such as :
22
20
23
- - 💾 ** Local Filesystem:** for local storage (e.g. via Node.js ` fs ` module)
24
21
- ☁️ ** S3 Buckets:** for remote storage in the cloud
22
+ - 💾 ** Local Filesystem:** for local storage (e.g. via Node.js ` fs ` module)
25
23
- 🧭 ** Origin Private File System:** for local storage in web apps
26
24
- 🌎 ** Relative URLs:** between resources on the web
27
25
26
+ ## Quickstart Guide
27
+
28
+ 1 . ** Model** your file structure with ` dir ` and ` file `
29
+ 2 . ** Get paths** , either:
30
+ - ** to a file/dir** with ` getPath `
31
+ - ** between files/dirs** with ` getRelativeFsPath ` or ` getRelativeUrlPath `
32
+
33
+ Here is a model to represent a HLS video package file structure and how to get paths with ` getPath ` and ` getRelativeUrlPath ` .
34
+
35
+ ``` ts
36
+ import { dir , file , getPath , getRelativeUrlPath } from ' @midzdotdev/path-master'
37
+
38
+ /* This is the file structure we're modelling:
39
+
40
+ .
41
+ └── videos
42
+ └── [videoId]
43
+ ├── master.m3u8
44
+ └── stream_[quality]
45
+ ├── playlist.m3u8
46
+ └── segment_[segmentId].ts
47
+ */
48
+
49
+ const hlsPackageModel = dir (
50
+ ({ videoId }: { videoId: number }) => ` videos/${videoId } ` ,
51
+ {
52
+ manifest: file (` master.m3u8 ` ),
53
+ variantStream: dir (
54
+ ({ quality }: { quality: 720 | 1080 }) => ` stream_${quality } ` ,
55
+ {
56
+ playlist: file (` playlist.m3u8 ` ),
57
+ segment: file (
58
+ ({ segmentId }: { segmentId: number }) => ` segment_${segmentId }.ts `
59
+ ),
60
+ }
61
+ ),
62
+ }
63
+ )
64
+
65
+ const hlsPackagePath = getPath (hlsPackageModel , ' ' , { videoId: 42 })
66
+ // result: "videos/42/"
67
+
68
+ const streamPlaylist = getPath (hlsPackageModel , ' variantStream.playlist' , {
69
+ videoId: 42 ,
70
+ quality: 720 ,
71
+ })
72
+ // result: "videos/42/stream_720/playlist.m3u8"
73
+
74
+ const masterPlaylistToVariantPlaylist = getRelativeUrlPath (
75
+ hlsPackageModel ,
76
+ [' manifest' , { videoId: 42 }],
77
+ [' variantStream.playlist' , { videoId: 42 , quality: 720 }]
78
+ )
79
+ // result: "stream_720/playlist.m3u8"
80
+ ```
81
+
82
+ <p align =" center " >
83
+ <img src =" https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExeTJxYmk3YnZyOXc1c2U5Y2cxdjdjbGJlanpmbGx1M3l5cGc0YWtraCZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/a0h7sAqON67nO/giphy.gif " style =" max-width : 300px " />
84
+ </p >
85
+
86
+ > If the Quickstart Guide doesn't make sense, don't worry! The rest of this README will cover everything you need to know.
87
+
88
+ # Table of Contents
89
+
90
+ - [ Introduction] ( #introduction )
91
+ - [ Installation] ( #installation )
92
+ - [ Conceptualising Models] ( #conceptualising-models )
93
+ - [ Abstracting large models] ( #abstracting-large-models )
94
+ - [ Create a Model] ( #create-a-model )
95
+ - [ Get Paths] ( #get-paths )
96
+ - [ Get Relative Paths] ( #get-relative-paths )
97
+ - [ Contributing] ( #contributing )
98
+
28
99
## Introduction
29
100
30
101
Making storage paths in any language is a painful process.
@@ -83,8 +154,6 @@ The following table gives us some examples of concrete paths for different nodes
83
154
84
155
> Note that the path is relative to the root of the model (represented by ` . ` [ in the psuedo-model] ( #psuedo-model ) ).
85
156
86
- Hopefully now modelling a file structure make sense as a concept. Let's move onto the code.
87
-
88
157
## Create a Model
89
158
90
159
The library exposes two helper functions ` file ` and ` dir ` for us to build our model.
@@ -125,56 +194,18 @@ const deepDir = dir('deep_dir', {
125
194
})
126
195
```
127
196
128
- ### Example: Modelling our HLS package
129
-
130
- Let's fully model [ our original example] ( #psuedo-model ) .
131
-
132
- Here is the desired psuedo-model copied for convenience:
197
+ > The path of a node in the model can span across multiple directories (e.g. ` videos/${videoId} ` above).
198
+ > This can help to produce a more concise model when dealing with deeply nested structures.
133
199
134
- ```
135
- .
136
- └── videos
137
- └── [videoId]
138
- ├── master.m3u8
139
- └── stream_[quality]
140
- ├── playlist.m3u8
141
- └── segment_[segmentId].ts
142
- ```
143
-
144
- Using our ` dir ` and ` file ` modelling functions, we can define our model:
145
-
146
- ``` ts
147
- import { dir , file } from ' @midzdotdev/path-master'
148
-
149
- const hlsPackageModel = dir (
150
- ({ videoId }: { videoId: number }) => ` videos/${videoId } ` ,
151
- {
152
- manifest: file (` master.m3u8 ` ),
153
- variantStream: dir (
154
- ({ quality }: { quality: 720 | 1080 }) => ` stream_${quality } ` ,
155
- {
156
- playlist: file (` playlist.m3u8 ` ),
157
- segment: file (
158
- ({ segmentId }: { segmentId: number }) => ` segment_${segmentId }.ts `
159
- ),
160
- }
161
- ),
162
- }
163
- )
164
- ```
165
-
166
- The path of a node in the model can span across multiple directories (e.g. ` videos/${videoId} ` above).
167
- This can help to produce a more concise model when dealing with deeply nested structures.
168
-
169
- ### Abstracting large models
200
+ ## Abstracting large models
170
201
171
202
If you're working with a very large model, it might be clearer to define parts of a model separately, then join them together into one main model.
172
203
173
204
If all the parts are together in a single file, then you can ` export ` the main model to remove any ambiguity about which model should be used in other parts of your application.
174
205
175
206
Ideally a model should fully describe the structure of a storage destination. This way your model's root aligns with the storage's root and the paths given by ` path-master ` can be used directly as absolute paths.
176
207
177
- ## Getting Paths
208
+ ## Get Paths
178
209
179
210
Now that we have a model, let's address the reason that we're here in the first place! Let's get some paths.
180
211
@@ -235,7 +266,7 @@ const segment11 = getPath(hlsPackageModel, 'variantStream.segment', {
235
266
236
267
> Notice that the type of the path is properly inferred from the model definition.
237
268
238
- ## Getting Relative Paths
269
+ ## Get Relative Paths
239
270
240
271
You can get relative paths between nodes, so long as they're in the same model.
241
272
@@ -246,7 +277,7 @@ The relative path from `a/b` to `a/c/d`:
246
277
- in a filesystem is ` ../c/d `
247
278
- in a URL is ` c/d `
248
279
249
- > Have a play around with this yourself to better understand the difference.
280
+ > You can have a play around with this yourself to better understand the difference.
250
281
>
251
282
> - Use the Node REPL with ` path.relative(from, to) ` for filesystem paths
252
283
> - Use the browser console with ` new URL(relativePath, fromUrl) ` for URL paths
@@ -256,17 +287,17 @@ As a result we have two separate functions for each use-case:
256
287
- filesystem paths: ` getRelativeFsPath `
257
288
- URL paths: ` getRelativeUrlPath `
258
289
259
- Both of these functions have an identical signature.
290
+ Both of these functions have an identical signature that looks like this .
260
291
261
292
``` ts
262
293
declare const x: (
263
- model : FileNode | DirNode ,
294
+ model : DirNode ,
264
295
from : string | [keypath : string , dependencies : {}],
265
296
to : string | [keypath : string , dependencies : {}]
266
297
) => string
267
298
` ` `
268
299
269
- > If the node specified by _from_ or _to_'s keypath does not require dependencies, then you can just pass the keypath string.
300
+ > When the node specified for _from_ or _to_ has no dependencies, then you can just pass the keypath string.
270
301
271
302
Since our example model being a HLS package only concerns itself with URLs, we'll demonstrate with ` getRelativeUrlPath ` .
272
303
0 commit comments