a collection of lightweight TypeScript packages for AT Protocol, the protocol powering Bluesky
atproto bluesky typescript npm
101
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(cache): hoist the actual walker function

Mary 1d1d0dae 34179d7b

+86 -59
+86 -59
packages/clients/cache/lib/walker.ts
··· 91 91 return identity; 92 92 } 93 93 94 - return (data) => (data === undefined ? data : innerWalker(data)); 94 + return createOptionalWalker(innerWalker); 95 95 } 96 96 97 97 if (isNullableSchema(schema)) { ··· 100 100 return identity; 101 101 } 102 102 103 - return (data) => (data === null ? data : innerWalker(data)); 103 + return createNullableWalker(innerWalker); 104 104 } 105 105 106 106 // primitive types - no walking needed ··· 136 136 return identity; 137 137 } 138 138 139 - return (data) => { 140 - // if entity, upsert to get cached reference (mutate in place) 141 - // if not entity, clone on first property change 142 - let entity = data as Record<string, unknown>; 143 - let cloned = entityTypeId !== undefined; 144 - 145 - if (entityTypeId !== undefined) { 146 - entity = ctx.upsertEntity(entityTypeId, entity) as Record<string, unknown>; 147 - } 148 - 149 - if (propWalkers !== undefined) { 150 - for (const [name, walk] of propWalkers) { 151 - const propValue = entity[name]; 152 - const walked = walk(propValue); 153 - 154 - if (walked !== propValue) { 155 - if (entityTypeId === undefined && !cloned) { 156 - entity = { ...entity }; 157 - cloned = true; 158 - } 159 - 160 - entity[name] = walked; 161 - } 162 - } 163 - } 164 - 165 - return entity; 166 - }; 139 + return createObjectWalker(ctx, entityTypeId, propWalkers); 167 140 } 168 141 169 142 #buildArrayWalker(schema: { item: BaseSchema }): WalkFn { ··· 173 146 return identity; 174 147 } 175 148 176 - return (data) => { 177 - const prev = data as unknown[]; 178 - let next: unknown[] | undefined; 179 - 180 - for (let i = 0; i < prev.length; i++) { 181 - const item = prev[i]; 182 - const walked = itemWalker(item); 183 - 184 - if (walked !== item) { 185 - if (next === undefined) { 186 - next = prev.slice(); 187 - } 188 - 189 - next[i] = walked; 190 - } 191 - } 192 - 193 - return next ?? prev; 194 - }; 149 + return createArrayWalker(itemWalker); 195 150 } 196 151 197 152 #buildVariantWalker(schema: VariantSchema): WalkFn { ··· 217 172 return identity; 218 173 } 219 174 220 - return (data) => { 221 - const obj = data as Record<string, unknown>; 222 - const type = obj.$type as string | undefined; 175 + return createVariantWalker(walkerMap); 176 + } 177 + } 178 + 179 + /** creates an object walker with minimal closure scope */ 180 + const createObjectWalker = ( 181 + ctx: WalkerContext, 182 + entityTypeId: EntityTypeId | undefined, 183 + propWalkers: [string, WalkFn][] | undefined, 184 + ): WalkFn => { 185 + return (data) => { 186 + let entity = data as Record<string, unknown>; 187 + let cloned = entityTypeId !== undefined; 188 + 189 + if (entityTypeId !== undefined) { 190 + entity = ctx.upsertEntity(entityTypeId, entity) as Record<string, unknown>; 191 + } 192 + 193 + if (propWalkers !== undefined) { 194 + for (const [name, walk] of propWalkers) { 195 + const propValue = entity[name]; 196 + const walked = walk(propValue); 223 197 224 - if (type === undefined) { 225 - return data; 198 + if (walked !== propValue) { 199 + if (entityTypeId === undefined && !cloned) { 200 + entity = { ...entity }; 201 + cloned = true; 202 + } 203 + 204 + entity[name] = walked; 205 + } 226 206 } 207 + } 227 208 228 - const memberWalker = walkerMap[type]; 229 - return memberWalker ? memberWalker(data) : data; 230 - }; 231 - } 232 - } 209 + return entity; 210 + }; 211 + }; 212 + 213 + /** creates an array walker with minimal closure scope */ 214 + const createArrayWalker = (itemWalker: WalkFn): WalkFn => { 215 + return (data) => { 216 + const prev = data as unknown[]; 217 + let next: unknown[] | undefined; 218 + 219 + for (let i = 0; i < prev.length; i++) { 220 + const item = prev[i]; 221 + const walked = itemWalker(item); 222 + 223 + if (walked !== item) { 224 + if (next === undefined) { 225 + next = prev.slice(); 226 + } 227 + 228 + next[i] = walked; 229 + } 230 + } 231 + 232 + return next ?? prev; 233 + }; 234 + }; 235 + 236 + /** creates a variant walker with minimal closure scope */ 237 + const createVariantWalker = (walkerMap: Record<string, WalkFn>): WalkFn => { 238 + return (data) => { 239 + const obj = data as Record<string, unknown>; 240 + const type = obj.$type as string | undefined; 241 + 242 + if (type === undefined) { 243 + return data; 244 + } 245 + 246 + const memberWalker = walkerMap[type]; 247 + return memberWalker ? memberWalker(data) : data; 248 + }; 249 + }; 250 + 251 + /** creates an optional walker with minimal closure scope */ 252 + const createOptionalWalker = (innerWalker: WalkFn): WalkFn => { 253 + return (data) => (data === undefined ? data : innerWalker(data)); 254 + }; 255 + 256 + /** creates a nullable walker with minimal closure scope */ 257 + const createNullableWalker = (innerWalker: WalkFn): WalkFn => { 258 + return (data) => (data === null ? data : innerWalker(data)); 259 + };