88} from "$lib/highlighter/catalog" ;
99
1010export const draftStorageKey = "dc-code-paste:draft:v1" ;
11+ export const draftHistoryStorageKey = "dc-code-paste:draft-history:v1" ;
12+ export const maxDraftHistoryCount = 10 ;
1113
1214export type DraftPreferences = {
1315 language : DcLanguageId ;
@@ -29,6 +31,11 @@ export type DraftSnapshot = {
2931 preferences : DraftPreferences ;
3032} ;
3133
34+ export type DraftHistorySnapshot = DraftSnapshot & {
35+ id : string ;
36+ createdAt : string ;
37+ } ;
38+
3239type DraftStorage = Pick < Storage , "getItem" | "setItem" | "removeItem" > ;
3340
3441function isRecord ( value : unknown ) : value is Record < string , unknown > {
@@ -122,6 +129,59 @@ function normalizeDraftPreferences(value: unknown): DraftPreferences | undefined
122129 } ;
123130}
124131
132+ function createSnapshotId ( ) {
133+ if ( typeof crypto !== "undefined" && typeof crypto . randomUUID === "function" ) {
134+ return crypto . randomUUID ( ) ;
135+ }
136+
137+ return `draft_${ Date . now ( ) . toString ( 36 ) } _${ Math . random ( ) . toString ( 36 ) . slice ( 2 , 10 ) } ` ;
138+ }
139+
140+ function normalizeDraftSnapshot ( value : unknown ) : DraftSnapshot | undefined {
141+ if ( ! isRecord ( value ) ) {
142+ return undefined ;
143+ }
144+
145+ if ( value . version !== 1 || typeof value . updatedAt !== "string" ) {
146+ return undefined ;
147+ }
148+
149+ if ( ! isJsonContent ( value . document ) ) {
150+ return undefined ;
151+ }
152+
153+ const preferences = normalizeDraftPreferences ( value . preferences ) ;
154+
155+ if ( ! preferences ) {
156+ return undefined ;
157+ }
158+
159+ return {
160+ version : 1 ,
161+ updatedAt : value . updatedAt ,
162+ document : value . document ,
163+ preferences,
164+ } ;
165+ }
166+
167+ function normalizeDraftHistorySnapshot ( value : unknown ) : DraftHistorySnapshot | undefined {
168+ if ( ! isRecord ( value ) || typeof value . id !== "string" || typeof value . createdAt !== "string" ) {
169+ return undefined ;
170+ }
171+
172+ const snapshot = normalizeDraftSnapshot ( value ) ;
173+
174+ if ( ! snapshot ) {
175+ return undefined ;
176+ }
177+
178+ return {
179+ ...snapshot ,
180+ id : value . id ,
181+ createdAt : value . createdAt ,
182+ } ;
183+ }
184+
125185export function createDraftSnapshot (
126186 document : JSONContent ,
127187 preferences : DraftPreferences ,
@@ -134,6 +194,22 @@ export function createDraftSnapshot(
134194 } ;
135195}
136196
197+ export function createDraftHistorySnapshot (
198+ document : JSONContent ,
199+ preferences : DraftPreferences ,
200+ ) : DraftHistorySnapshot {
201+ const timestamp = new Date ( ) . toISOString ( ) ;
202+
203+ return {
204+ version : 1 ,
205+ id : createSnapshotId ( ) ,
206+ createdAt : timestamp ,
207+ updatedAt : timestamp ,
208+ document,
209+ preferences,
210+ } ;
211+ }
212+
137213export function parseDraftSnapshot ( value : string ) : DraftSnapshot | undefined {
138214 let parsed : unknown ;
139215
@@ -143,30 +219,26 @@ export function parseDraftSnapshot(value: string): DraftSnapshot | undefined {
143219 return undefined ;
144220 }
145221
146- if ( ! isRecord ( parsed ) ) {
147- return undefined ;
148- }
222+ return normalizeDraftSnapshot ( parsed ) ;
223+ }
149224
150- if ( parsed . version !== 1 || typeof parsed . updatedAt !== "string" ) {
151- return undefined ;
152- }
225+ export function parseDraftHistorySnapshots ( value : string ) : DraftHistorySnapshot [ ] {
226+ let parsed : unknown ;
153227
154- if ( ! isJsonContent ( parsed . document ) ) {
155- return undefined ;
228+ try {
229+ parsed = JSON . parse ( value ) ;
230+ } catch {
231+ return [ ] ;
156232 }
157233
158- const preferences = normalizeDraftPreferences ( parsed . preferences ) ;
159-
160- if ( ! preferences ) {
161- return undefined ;
234+ if ( ! Array . isArray ( parsed ) ) {
235+ return [ ] ;
162236 }
163237
164- return {
165- version : 1 ,
166- updatedAt : parsed . updatedAt ,
167- document : parsed . document ,
168- preferences,
169- } ;
238+ return parsed
239+ . map ( ( item ) => normalizeDraftHistorySnapshot ( item ) )
240+ . filter ( ( item ) : item is DraftHistorySnapshot => Boolean ( item ) )
241+ . slice ( 0 , maxDraftHistoryCount ) ;
170242}
171243
172244export function readDraftSnapshot ( storage : DraftStorage ) : DraftSnapshot | undefined {
@@ -178,6 +250,15 @@ export function readDraftSnapshot(storage: DraftStorage): DraftSnapshot | undefi
178250 }
179251}
180252
253+ export function readDraftHistorySnapshots ( storage : DraftStorage ) : DraftHistorySnapshot [ ] {
254+ try {
255+ const stored = storage . getItem ( draftHistoryStorageKey ) ;
256+ return stored ? parseDraftHistorySnapshots ( stored ) : [ ] ;
257+ } catch {
258+ return [ ] ;
259+ }
260+ }
261+
181262export function writeDraftSnapshot ( storage : DraftStorage , snapshot : DraftSnapshot ) : boolean {
182263 try {
183264 storage . setItem ( draftStorageKey , JSON . stringify ( snapshot ) ) ;
@@ -187,6 +268,44 @@ export function writeDraftSnapshot(storage: DraftStorage, snapshot: DraftSnapsho
187268 }
188269}
189270
271+ export function writeDraftHistorySnapshots (
272+ storage : DraftStorage ,
273+ snapshots : DraftHistorySnapshot [ ] ,
274+ ) : boolean {
275+ try {
276+ storage . setItem (
277+ draftHistoryStorageKey ,
278+ JSON . stringify ( snapshots . slice ( 0 , maxDraftHistoryCount ) ) ,
279+ ) ;
280+ return true ;
281+ } catch {
282+ return false ;
283+ }
284+ }
285+
286+ export function appendDraftHistorySnapshot (
287+ storage : DraftStorage ,
288+ snapshot : DraftHistorySnapshot ,
289+ ) : DraftHistorySnapshot [ ] {
290+ const current = readDraftHistorySnapshots ( storage ) ;
291+ const next = [ snapshot , ...current . filter ( ( item ) => item . id !== snapshot . id ) ] . slice (
292+ 0 ,
293+ maxDraftHistoryCount ,
294+ ) ;
295+
296+ return writeDraftHistorySnapshots ( storage , next ) ? next : current ;
297+ }
298+
299+ export function deleteDraftHistorySnapshot (
300+ storage : DraftStorage ,
301+ id : string ,
302+ ) : DraftHistorySnapshot [ ] {
303+ const current = readDraftHistorySnapshots ( storage ) ;
304+ const next = current . filter ( ( item ) => item . id !== id ) ;
305+
306+ return writeDraftHistorySnapshots ( storage , next ) ? next : current ;
307+ }
308+
190309export function clearDraftSnapshot ( storage : DraftStorage ) : boolean {
191310 try {
192311 storage . removeItem ( draftStorageKey ) ;
@@ -195,3 +314,12 @@ export function clearDraftSnapshot(storage: DraftStorage): boolean {
195314 return false ;
196315 }
197316}
317+
318+ export function clearDraftHistorySnapshots ( storage : DraftStorage ) : boolean {
319+ try {
320+ storage . removeItem ( draftHistoryStorageKey ) ;
321+ return true ;
322+ } catch {
323+ return false ;
324+ }
325+ }
0 commit comments