@@ -18,7 +18,7 @@ import { derived, writable } from 'svelte/store';
1818/**
1919 *@type {import('svelte/store').Writable<State> }
2020 */
21- const _state = writable ( {
21+ const { subscribe , set , update } = writable ( {
2222status :'initial' ,
2323stubs :[ ] ,
2424selected :null ,
@@ -34,100 +34,100 @@ const _state = writable({
3434} ) ;
3535
3636export const state = {
37- subscribe :_state . subscribe ,
37+ subscribe,
38+
3839/**@param {import('$lib/types').FileStub } file */
3940update_file :( file ) => {
40- _state . update ( ( state ) => {
41- state . status = 'update' ;
42- state . stubs = state . stubs . map ( ( stub ) => {
41+ update ( ( state ) => ( {
42+ ...state ,
43+ status :'update' ,
44+ stubs :state . stubs . map ( ( stub ) => {
4345if ( stub . name === file . name ) {
4446return file ;
4547}
4648return stub ;
47- } ) ;
48- state . last_updated = file ;
49- return state ;
50- } ) ;
49+ } ) ,
50+ last_updated :file
51+ } ) ) ;
5152} ,
53+
5254/**@param {import('$lib/types').Stub[] } [stubs] */
5355set_stubs :( stubs ) => {
54- _state . update ( ( state ) => {
55- state . status = 'set' ;
56- state . stubs = stubs || state . stubs ;
57- state . last_updated = undefined ;
58- return state ;
59- } ) ;
56+ update ( ( state ) => ( {
57+ ... state ,
58+ status : 'set' ,
59+ stubs : stubs ?? state . stubs ,
60+ last_updated : undefined
61+ } ) ) ;
6062} ,
63+
6164/**@param {import('$lib/types').Exercise } exercise */
6265switch_exercise :( exercise ) => {
63- _state . update ( ( state ) => {
64- const solution = { ...exercise . a } ;
65- const editing_constraints = {
66- create :exercise . editing_constraints . create ,
67- remove :exercise . editing_constraints . remove
68- } ;
69-
70- // TODO should exercise.a/b be an array in the first place?
71- for ( const stub of Object . values ( exercise . b ) ) {
72- if ( stub . type === 'file' && stub . contents . startsWith ( '__delete' ) ) {
73- // remove file
74- if ( ! editing_constraints . remove . includes ( stub . name ) ) {
75- editing_constraints . remove . push ( stub . name ) ;
76- }
77- delete solution [ stub . name ] ;
78- } else if ( stub . name . endsWith ( '/__delete' ) ) {
79- // remove directory
80- const parent = stub . name . slice ( 0 , stub . name . lastIndexOf ( '/' ) ) ;
81- if ( ! editing_constraints . remove . includes ( parent ) ) {
82- editing_constraints . remove . push ( parent ) ;
83- }
84- delete solution [ parent ] ;
85- for ( const k in solution ) {
86- if ( k . startsWith ( parent + '/' ) ) {
87- delete solution [ k ] ;
88- }
89- }
90- } else {
91- if ( ! solution [ stub . name ] && ! editing_constraints . create . includes ( stub . name ) ) {
92- editing_constraints . create . push ( stub . name ) ;
66+ const solution = { ...exercise . a } ;
67+ const editing_constraints = {
68+ create :exercise . editing_constraints . create ,
69+ remove :exercise . editing_constraints . remove
70+ } ;
71+
72+ // TODO should exercise.a/b be an array in the first place?
73+ for ( const stub of Object . values ( exercise . b ) ) {
74+ if ( stub . type === 'file' && stub . contents . startsWith ( '__delete' ) ) {
75+ // remove file
76+ if ( ! editing_constraints . remove . includes ( stub . name ) ) {
77+ editing_constraints . remove . push ( stub . name ) ;
78+ }
79+ delete solution [ stub . name ] ;
80+ } else if ( stub . name . endsWith ( '/__delete' ) ) {
81+ // remove directory
82+ const parent = stub . name . slice ( 0 , stub . name . lastIndexOf ( '/' ) ) ;
83+ if ( ! editing_constraints . remove . includes ( parent ) ) {
84+ editing_constraints . remove . push ( parent ) ;
85+ }
86+ delete solution [ parent ] ;
87+ for ( const k in solution ) {
88+ if ( k . startsWith ( parent + '/' ) ) {
89+ delete solution [ k ] ;
9390}
94- solution [ stub . name ] = exercise . b [ stub . name ] ;
9591}
92+ } else {
93+ if ( ! solution [ stub . name ] && ! editing_constraints . create . includes ( stub . name ) ) {
94+ editing_constraints . create . push ( stub . name ) ;
95+ }
96+ solution [ stub . name ] = exercise . b [ stub . name ] ;
9697}
98+ }
9799
98- state . status = 'switch' ;
99- state . stubs = Object . values ( exercise . a ) ;
100- state . exercise = {
100+ set ( {
101+ status :'switch' ,
102+ stubs :Object . values ( exercise . a ) ,
103+ exercise :{
101104initial :Object . values ( exercise . a ) ,
102105solution,
103106editing_constraints,
104107scope :exercise . scope
105- } ;
106- state . last_updated = undefined ;
107- state . selected = exercise . focus ;
108- return state ;
108+ } ,
109+ last_updated :undefined ,
110+ selected :exercise . focus
109111} ) ;
110112} ,
113+
111114toggle_completion :( ) => {
112- _state . update ( ( state ) => {
113- if ( is_completed ( state ) ) {
114- state . stubs = state . exercise . initial ;
115- } else {
116- state . stubs = Object . values ( state . exercise . solution ) ;
117- }
118- state . status = 'set' ;
119- state . last_updated = undefined ;
120- return state ;
121- } ) ;
115+ update ( ( state ) => ( {
116+ ...state ,
117+ status :'set' ,
118+ stubs :is_completed ( state ) ?state . exercise . initial :Object . values ( state . exercise . solution ) ,
119+ last_updated :undefined
120+ } ) ) ;
122121} ,
122+
123123/**@param {string | null } name */
124124select_file :( name ) => {
125- _state . update ( ( state ) => {
126- state . status = 'select' ;
127- state . selected = name ;
128- state . last_updated = undefined ;
129- return state ;
130- } ) ;
125+ update ( ( state ) => ( {
126+ ... state ,
127+ status : 'select' ,
128+ selected : name ,
129+ last_updated : undefined
130+ } ) ) ;
131131}
132132} ;
133133