1- # path-master
2-
31[ ![ JSR] ( https://jsr.io/badges/@midzdotdev/path-master )] ( https://jsr.io/@midzdotdev/path-master )
42[ ![ Release Workflow] ( https://github.com/midzdotdev/path-master/actions/workflows/release.yml/badge.svg )] ( https://github.com/midzdotdev/path-master/actions/workflows/release.yml )
53
@@ -10,21 +8,94 @@ You can think of `path-master` as providing structure to files in the same way t
108Path Master provides a whole host of benefits:
119
1210- 🏡 ** 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
1511- 📊 ** Parameterised:** paths are as dynamic as you need
12+ - ✨ ** Type-safe:** parameters are typed, and path types are inferred
1613- 📈 ** Incremental:** model a complete file structure or just parts of it
14+ - 🧬 ** Consistent:** standardises your path generation
1715
1816> This library does not modify any filesystem directly,
1917> it's solely for modelling and generating paths.
2018
21- The applications for this are endless, but commonly useful with :
19+ It can be used anywhere paths are used, such as :
2220
23- - 💾 ** Local Filesystem:** for local storage (e.g. via Node.js ` fs ` module)
2421- ☁️ ** S3 Buckets:** for remote storage in the cloud
22+ - 💾 ** Local Filesystem:** for local storage (e.g. via Node.js ` fs ` module)
2523- 🧭 ** Origin Private File System:** for local storage in web apps
2624- 🌎 ** Relative URLs:** between resources on the web
2725
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+
2899## Introduction
29100
30101Making 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
83154
84155> Note that the path is relative to the root of the model (represented by ` . ` [ in the psuedo-model] ( #psuedo-model ) ).
85156
86- Hopefully now modelling a file structure make sense as a concept. Let's move onto the code.
87-
88157## Create a Model
89158
90159The library exposes two helper functions ` file ` and ` dir ` for us to build our model.
@@ -125,56 +194,18 @@ const deepDir = dir('deep_dir', {
125194})
126195```
127196
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.
133199
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
170201
171202If 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.
172203
173204If 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.
174205
175206Ideally 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.
176207
177- ## Getting Paths
208+ ## Get Paths
178209
179210Now that we have a model, let's address the reason that we're here in the first place! Let's get some paths.
180211
@@ -235,7 +266,7 @@ const segment11 = getPath(hlsPackageModel, 'variantStream.segment', {
235266
236267> Notice that the type of the path is properly inferred from the model definition.
237268
238- ## Getting Relative Paths
269+ ## Get Relative Paths
239270
240271You can get relative paths between nodes, so long as they're in the same model.
241272
@@ -246,7 +277,7 @@ The relative path from `a/b` to `a/c/d`:
246277- in a filesystem is ` ../c/d `
247278- in a URL is ` c/d `
248279
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.
250281>
251282> - Use the Node REPL with ` path.relative(from, to) ` for filesystem paths
252283> - 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:
256287- filesystem paths: ` getRelativeFsPath `
257288- URL paths: ` getRelativeUrlPath `
258289
259- Both of these functions have an identical signature.
290+ Both of these functions have an identical signature that looks like this .
260291
261292``` ts
262293declare const x: (
263- model : FileNode | DirNode ,
294+ model : DirNode ,
264295 from : string | [keypath : string , dependencies : {}],
265296 to : string | [keypath : string , dependencies : {}]
266297) => string
267298` ` `
268299
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.
270301
271302Since our example model being a HLS package only concerns itself with URLs, we'll demonstrate with ` getRelativeUrlPath ` .
272303
0 commit comments