UNPKG

5.71 kBJavaScriptView Raw
1/*
2 constructor should define the pacakage's name
3 by default this will be added to the x-powered-by header of all responses
4*/
5class SolidLocalStorage {
6 constructor() {
7 this.prefix = "ls"
8 this.name = "solid-rest-localStorage-1.0.0"
9 localStorage.setItem( "/", " " );
10 }
11
12/*
13 getObjectType(pathname,options)
14 * trys to find pathname in storage
15 * if found, sets exists to true
16 * sets type to "Container" or "Resource" or undefined
17 * returns an array [type,exists]
18*/
19async getObjectType(pathname,options){
20 let type = (pathname.match(/\/$/)) ? "Container" : "Resource";
21 pathname = pathname.replace(/\/$/,'') // REMOVE TRAILING SLASH
22 let exists = false
23 let keys = Object.keys(localStorage)
24 for(var k in keys) {
25 let item = keys[k]
26 if(type==="Container" && item.startsWith(pathname)){ exists=true; break }
27 if(item === pathname){ exists=true; break }
28 }
29 return [type,exists]
30}
31
32/*
33 getResource(pathname,options)
34 * gets a resource
35 * on success, returns [ 200, resourceContents, optionalHeader ]
36 * on failure, returns [ 500, undefined, optionalHeader ]
37*/
38async getResource(pathname,options){
39 try {
40 let body = localStorage.getItem( pathname );
41 return Promise.resolve( [ 200, body ] )
42 }
43 catch(e){ Promise.resolve( [500] ) }
44}
45
46/*
47 getContainer(pathname,options)
48 * returns an array of the container's contained resource names
49 * OR returns a turtle representation of the container and contents
50*/
51async getContainer(pathname,options) {
52 const files = Object.keys(localStorage)
53 .filter(path => path.startsWith(pathname) && path != pathname) // Only children
54 .map(path => path.substr(pathname.length))
55 .filter(path => !path.slice(0, -1).includes("/")) // Only include direct children
56
57 return files
58}
59
60dump(pathname,options) {
61 let keys = Object.keys(localStorage).filter(k=>{
62 if(!k.match(/(setItem|getItem|removeItem)/)) return k
63 }).map(m=>{
64 console.log( m, localStorage.getItem(m) )
65 })
66}
67clear() {
68 let keys = Object.keys(localStorage).filter(k=>{
69 if(!k.match(/(setItem|getItem|removeItem)/)) return k
70 }).map(item=>{
71 this.deleteResource(item)
72 })
73}
74
75/*
76 putResource(pathname,options)
77 * creates a single Resource
78 * on success : status = 201
79 * on error : status = 500
80 * returns [status,undefined,optionalHeader]
81*/
82async putResource(pathname,options){
83 options = options || {};
84 options.body = options.body || "";
85 try {
86 localStorage.setItem( pathname, options.body );
87 return Promise.resolve( [201] )
88 }
89 catch(e){ console.log(e); return Promise.resolve( [500] ) }
90}
91
92/*
93 postContainer(pathname,options)
94 * creates a single Container
95 * on success : status = 201
96 * on error : status = 500
97 * returns [status,undefined,optionalHeader]
98*/
99async postContainer(pathname,options){
100 pathname = pathname + '/' // because wasn't on slug
101 return this.putResource(pathname,options)
102}
103
104/*
105 deleteResource(pathname,options)
106 * deletes a resource
107 * on success, returns [200,undefined,optionalHeader]
108 * on failure, returns [500,undefined,optionalHeader]
109*/
110async deleteResource(pathname,options){
111 try {
112 localStorage.removeItem(pathname)
113 return Promise.resolve( [200] )
114 }
115 catch(e){ return Promise.resolve( [500] ) }
116}
117
118/*
119 deleteContainer(pathname,options)
120 * if container is not empty, returns [409,undefined,optionalHeader]
121 * else deletes container
122 * on success, returns [200,undefined,optionalHeader]
123 * on failure, returns [500,undefined,optionalHeader]
124*/
125async deleteContainer(pathname,options){
126 let files = await this.getContainer(pathname,options)
127 if( files.length ){ return Promise.resolve( [409] ) }
128 return await this.deleteResource(pathname,options)
129}
130
131async makeContainers(pathname,options){
132 const inexistentParents = []
133
134 // Get all parents which need to be created
135 let curParent = getParent(pathname)
136 while (curParent && !(await this.getObjectType(curParent))[1]) {
137 inexistentParents.push(curParent)
138 curParent = getParent(curParent)
139 }
140 if (!curParent) // Should not happen, that we get to the root
141 return [500]
142
143 // Create missing parents
144 while (inexistentParents.length) {
145 // postContainer expects an url without '/' at the end
146 await this.postContainer(inexistentParents.pop().slice(0, -1))
147 }
148 return [201]
149}
150}
151
152/**
153 * return parent url with / at the end.
154 * If no parent exists return null
155 * @param {string} url
156 * @returns {string|null}
157 */
158function getParent(url) {
159 while (url.endsWith('/'))
160 url = url.slice(0, -1)
161 if (!url.includes('/'))
162 return null
163 return url.substring(0, url.lastIndexOf('/')) + '/'
164}
165
166/*
167 OPTIONAL METHODS
168
169 see solid-rest.js code for examples of the defaults
170 optionally provide your own to replace or augment the behavior
171
172 text(stream)
173 * response method to pipe text body
174 * receives response body, returns piped string
175 json(string)
176 * response method to parse json body
177 * receives response body returns a json object
178 container2turtle(pathname,options,contentsArray)
179 * iterates over container's contents, creates a turtle representation
180 * returns [200, turtleContents, optionalHeader]
181 getHeaders(pathname,options)
182 * returns header fields to replace or augment default headers
183*/
184
185/*
186 if it should work in nodejs, export the object
187*/
188if(typeof window==="undefined") {
189 alert = (msg) => console.log(msg)
190 localStorage = {
191 getItem : (key) => { return localStorage[key] },
192 removeItem : (key) => { delete localStorage[key] },
193 setItem : (key,val) => { localStorage[key]=val },
194 }
195 module.exports = SolidLocalStorage
196}