@hamak/ui-store-impl 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/es2015/fs/commands/fs-commands.js +311 -0
  3. package/dist/es2015/fs/commands/structure-commands.js +21 -0
  4. package/dist/es2015/fs/core/fs-adapter.js +123 -0
  5. package/dist/es2015/fs/core/fs-facade.js +78 -0
  6. package/dist/es2015/fs/index.js +9 -0
  7. package/dist/es2015/fs/utils/data-updater.js +244 -0
  8. package/dist/es2015/fs/utils/deep-equal.js +28 -0
  9. package/dist/es2015/index.js +1 -0
  10. package/dist/fs/commands/fs-commands.d.ts +96 -0
  11. package/dist/fs/commands/fs-commands.d.ts.map +1 -0
  12. package/dist/fs/commands/fs-commands.js +311 -0
  13. package/dist/fs/commands/structure-commands.d.ts +76 -0
  14. package/dist/fs/commands/structure-commands.d.ts.map +1 -0
  15. package/dist/fs/commands/structure-commands.js +21 -0
  16. package/dist/fs/core/fs-adapter.d.ts +57 -0
  17. package/dist/fs/core/fs-adapter.d.ts.map +1 -0
  18. package/dist/fs/core/fs-adapter.js +123 -0
  19. package/dist/fs/core/fs-facade.d.ts +37 -0
  20. package/dist/fs/core/fs-facade.d.ts.map +1 -0
  21. package/dist/fs/core/fs-facade.js +78 -0
  22. package/dist/fs/index.d.ts +7 -0
  23. package/dist/fs/index.d.ts.map +1 -0
  24. package/dist/fs/index.js +9 -0
  25. package/dist/fs/utils/data-updater.d.ts +36 -0
  26. package/dist/fs/utils/data-updater.d.ts.map +1 -0
  27. package/dist/fs/utils/data-updater.js +248 -0
  28. package/dist/fs/utils/deep-equal.d.ts +5 -0
  29. package/dist/fs/utils/deep-equal.d.ts.map +1 -0
  30. package/dist/fs/utils/deep-equal.js +28 -0
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -0
  34. package/package.json +8 -5
  35. package/src/fs/commands/fs-commands.ts +406 -0
  36. package/src/fs/commands/structure-commands.ts +105 -0
  37. package/src/fs/core/fs-adapter.ts +180 -0
  38. package/src/fs/core/fs-facade.ts +100 -0
  39. package/src/fs/index.ts +11 -0
  40. package/src/fs/utils/data-updater.ts +273 -0
  41. package/src/fs/utils/deep-equal.ts +35 -0
  42. package/src/index.ts +1 -0
@@ -0,0 +1,406 @@
1
+ import {
2
+ DirectoryNode,
3
+ FileNode,
4
+ FileSystemNode,
5
+ FileSystemState,
6
+ FileContentSchema,
7
+ fileSystemNodeInitialState,
8
+ FileSystemNodeState,
9
+ Holder
10
+ } from '@hamak/ui-store-api';
11
+ import { Pathway } from '@hamak/navigation-utils';
12
+ import { StructureNodeCommand } from './structure-commands';
13
+ import { DataUpdater } from '../utils/data-updater';
14
+ import { produce, current, isDraft, original } from 'immer';
15
+ import { deepEqual } from '../utils/deep-equal';
16
+
17
+ /**
18
+ * Base interface for filesystem commands
19
+ */
20
+ export interface FsCommandBase {
21
+ name : 'mkdir' | 'set-file' | 'remove' | 'update-file-content' | 'set-file-content'
22
+ path : string | string[]
23
+ }
24
+
25
+ /**
26
+ * Create directory command
27
+ */
28
+ export interface MkdirCommand extends FsCommandBase{
29
+ name : 'mkdir'
30
+ parents? : boolean
31
+ }
32
+
33
+ /**
34
+ * Remove file or directory command
35
+ */
36
+ export interface RemoveCommand extends FsCommandBase{
37
+ name : 'remove'
38
+ recursive? : boolean
39
+ }
40
+
41
+ /**
42
+ * Set file command (create or update)
43
+ */
44
+ export interface SetFileCommand extends FsCommandBase{
45
+ name : 'set-file'
46
+ content : any
47
+ schema : FileContentSchema
48
+ override? : boolean
49
+ contentIsPresent? : boolean
50
+ }
51
+
52
+ /**
53
+ * Update file content with structure command
54
+ */
55
+ export interface UpdateFileContentCommand extends FsCommandBase{
56
+ name : 'update-file-content'
57
+ contentCommand : StructureNodeCommand
58
+ }
59
+
60
+ /**
61
+ * Set file content directly
62
+ */
63
+ export interface SetFileContentCommand extends FsCommandBase{
64
+ name : 'set-file-content'
65
+ content : any,
66
+ fromRemote?: boolean
67
+ }
68
+
69
+ /**
70
+ * Union type for all filesystem commands
71
+ */
72
+ export type FileSystemCommand =
73
+ | MkdirCommand
74
+ | RemoveCommand
75
+ | SetFileCommand
76
+ | UpdateFileContentCommand
77
+ | SetFileContentCommand
78
+
79
+ /**
80
+ * Convert path to steps array
81
+ */
82
+ export function pathSteps(path : string | string[]) : string[] {
83
+ if(Array.isArray(path)){
84
+ return path
85
+ }
86
+
87
+ return path.split('/').filter(s => s.trim().length > 0)
88
+ }
89
+
90
+ /**
91
+ * Get parent path steps
92
+ */
93
+ export function parentPathSteps(path : string | string[]) : string[] {
94
+ const steps = pathSteps(path)
95
+ return steps.length > 0 ? steps.slice(0, steps.length - 1) : steps
96
+ }
97
+
98
+ /**
99
+ * Get filesystem node at path
100
+ */
101
+ export function getFileSystemNode(fsNode: FileSystemNode, path : string | string[]) : FileSystemNode | undefined {
102
+ const steps = pathSteps(path)
103
+ let result : FileSystemNode | undefined = fsNode
104
+ for(let i = 0; i < steps.length; i++) {
105
+ const step = steps[i]
106
+ if (result === undefined){
107
+ return undefined
108
+ } else if(result.type === 'directory'){
109
+ result = result.children[step]
110
+ } else {
111
+ return undefined
112
+ }
113
+ }
114
+
115
+ return result
116
+ }
117
+
118
+ /**
119
+ * Create a directory node
120
+ */
121
+ function createDirectoryNode(step: string) : DirectoryNode{
122
+ return {
123
+ type: 'directory',
124
+ state: fileSystemNodeInitialState(),
125
+ name: step,
126
+ children: {}
127
+ };
128
+ }
129
+
130
+ /**
131
+ * Create a file node
132
+ */
133
+ function createFileNode(name: string, content : any, schema : FileContentSchema, state : FileSystemNodeState) : FileNode{
134
+ return {type: 'file', name, content, schema, state};
135
+ }
136
+
137
+ /**
138
+ * FileSystem command handler - executes filesystem operations
139
+ */
140
+ export class FileSystemCommandHandler {
141
+ readonly contentCommandHandler = new FileContentCommandHandler()
142
+
143
+ execute(state: FileSystemState, command: FileSystemCommand): FileSystemState {
144
+ switch (command.name) {
145
+ case 'mkdir': return this.executeMkdir(state, command)
146
+ case 'set-file': return this.executeSetFile(state, command)
147
+ case 'update-file-content' : return this.executeContentCommand(state, command)
148
+ case 'set-file-content' : return this.executeSetContentCommand(state, command)
149
+ case 'remove': return this.executeRemove(state, command)
150
+ }
151
+ }
152
+
153
+ private executeMkdir(state: FileSystemState, command : MkdirCommand) : FileSystemState{
154
+ const {path, parents} = command
155
+ const steps = pathSteps(path)
156
+
157
+ return produce(state, draft => {
158
+ const {root} = draft
159
+ let dir = root
160
+ for(let i = 0; i < steps.length; i++){
161
+ const step = steps[i]
162
+ if(i + 1 === steps.length){
163
+ // Last step is the element to create
164
+ if(dir.children[step] === undefined){
165
+ dir.children[step] = createDirectoryNode(step)
166
+ }
167
+ }else {
168
+ let child = dir.children[step]
169
+ if(child === undefined){
170
+ if(parents === true){
171
+ child = createDirectoryNode(step)
172
+ dir.children[step] = child
173
+ }else {
174
+ return
175
+ }
176
+ }else if(child.type === 'directory'){
177
+ dir = child
178
+ }else {
179
+ return;
180
+ }
181
+
182
+ dir = child
183
+ }
184
+ }
185
+ })
186
+ }
187
+
188
+
189
+ private executeRemove(state: FileSystemState, command : RemoveCommand) : FileSystemState{
190
+ const {path, recursive} = command
191
+ const steps = pathSteps(path)
192
+
193
+ return produce(state, draft => {
194
+ const {root} = draft
195
+ const parentDir = getFileSystemNode(root, steps.slice(0, steps.length - 1))
196
+ if(parentDir === undefined ){
197
+ return
198
+ }
199
+
200
+ if(parentDir.type === 'directory'){
201
+ const last = steps[steps.length - 1]
202
+ const child = parentDir.children[last]
203
+ if(child?.type === 'directory'
204
+ && Object.keys(child.children).length > 0
205
+ && !(recursive === true) ){
206
+ return;
207
+ }
208
+
209
+ delete parentDir.children[last]
210
+ }
211
+ })
212
+ }
213
+
214
+ private executeSetFile(state: FileSystemState, command : SetFileCommand) : FileSystemState{
215
+ const {path, content, schema, override, contentIsPresent} = command
216
+ const steps = pathSteps(path)
217
+
218
+ return produce(state, draft => {
219
+ const {root} = draft
220
+ const parentPath = steps.slice(0, steps.length - 1);
221
+ const parentDir = getFileSystemNode(root, parentPath)
222
+ if(parentDir === undefined ){
223
+ return
224
+ }
225
+
226
+ if(parentDir.type === 'directory'){
227
+ const last = steps[steps.length - 1]
228
+ const child = parentDir.children[last]
229
+ if(child === undefined || override === true){
230
+ parentDir.children[last] = createFileNode(last, content, schema, fileSystemNodeInitialState(contentIsPresent))
231
+ } else {
232
+ console.warn(`File already exists at location`, path)
233
+ }
234
+ }else{
235
+ console.warn(`Parent file is not directory`, parentPath)
236
+ }
237
+ })
238
+ }
239
+
240
+
241
+ private executeContentCommand(state: FileSystemState, command : UpdateFileContentCommand) : FileSystemState{
242
+ const {path, contentCommand} = command
243
+
244
+ return produce(state, draft => {
245
+ const {root} = draft
246
+ const fileNode = getFileSystemNode(root, path)
247
+
248
+ if(fileNode !== undefined){
249
+ if(fileNode.type === 'file'){
250
+ this.contentCommandHandler.execute(fileNode, contentCommand);
251
+
252
+ const previousFile = getFileSystemNode(state.root, path)
253
+ const previousContent = previousFile?.type === "file" ? previousFile.content : undefined
254
+
255
+ this.contentMayChange(fileNode);
256
+ }else{
257
+ console.warn(`Not a file at location`, path)
258
+ }
259
+ }else{
260
+ console.warn(`No file found at location`, path)
261
+ }
262
+
263
+ })
264
+ }
265
+
266
+
267
+ private contentMayChange(fileNode: FileNode) {
268
+ const changed = ! deepEqual(this.original(fileNode.content), this.current(fileNode.content))
269
+ if(changed){
270
+ if (fileNode.state === undefined) {
271
+ fileNode.state = fileSystemNodeInitialState()
272
+ }
273
+ fileNode.state.contentHistory.push(this.original(fileNode.content))
274
+
275
+ // check compared to memo modification status
276
+ if (fileNode.state.memo !== undefined) {
277
+ const memo = fileNode.state.memo
278
+ memo.modified = !deepEqual(this.current(memo.originalContent), this.current(fileNode.content))
279
+ }
280
+ }
281
+ }
282
+
283
+ private executeSetContentCommand(state: FileSystemState, command : SetFileContentCommand) : FileSystemState{
284
+ const {path, content, fromRemote} = command
285
+
286
+ return produce(state, draft => {
287
+ const {root} = draft
288
+ const fileNode = getFileSystemNode(root, path)
289
+
290
+ if(fileNode !== undefined){
291
+ if(fileNode.type === 'file'){
292
+ fileNode.content = content
293
+ if(fileNode.state === undefined){
294
+ fileNode.state = fileSystemNodeInitialState(true)
295
+ }
296
+ if(fromRemote){
297
+ fileNode.state.contentLoaded = true
298
+ if(fileNode.state.memo === undefined){
299
+ fileNode.state.memo = {originalContent: {value: content}, modified: false}
300
+ } else {
301
+ const memo = fileNode.state.memo
302
+ memo.originalContent = {value: content}
303
+ memo.modified = false
304
+ }
305
+ } else {
306
+ this.contentMayChange(fileNode)
307
+ }
308
+ }else{
309
+ console.warn(`Not a file at location`, path)
310
+ }
311
+ }else{
312
+ console.warn(`No file found at location`, path)
313
+ }
314
+
315
+ })
316
+ }
317
+
318
+ protected current<T = any>(o : T):T{
319
+ if(o === null || o === undefined){
320
+ return o
321
+ }
322
+
323
+ return isDraft(o) ? current(o) : o
324
+ }
325
+
326
+ protected original<T = any>(o : T):T | undefined{
327
+ if(o === null || o === undefined){
328
+ return o
329
+ }
330
+
331
+ return isDraft(o) ? original(o) : o
332
+ }
333
+ }
334
+
335
+ /**
336
+ * File content command handler - handles structure commands on file content
337
+ */
338
+ export class FileContentCommandHandler {
339
+ readonly updater = new DataUpdater()
340
+
341
+ execute(file : FileNode, command: StructureNodeCommand) {
342
+ switch (command.name) {
343
+ case 'add-at':{
344
+ this.executeAdd(file, command)
345
+ }break
346
+ case 'insert-at':{
347
+ this.executeInsert(file, command)
348
+ }break
349
+ case 'set-at':{
350
+ this.executeSet(file, command)
351
+ } break
352
+ case 'delete-at': {
353
+ this.executeDelete(file, command)
354
+ } break
355
+ case 'batch-update': {
356
+ this.executeBatch(file, command)
357
+ } break
358
+ }
359
+ }
360
+
361
+ private executeDelete(file : FileNode, command: any) {
362
+ const {itinerary} = command
363
+ if (itinerary === undefined) {
364
+ file.content = undefined
365
+ }
366
+
367
+ const {content} = file
368
+ this.updater.executeDelete(content, itinerary)
369
+ }
370
+
371
+ private executeSet(file : FileNode, command: any) {
372
+ const {itinerary, value} = command
373
+ if (itinerary === undefined) {
374
+ file.content = value
375
+ }
376
+
377
+ const {content} = file
378
+ this.updater.executeSet(content, itinerary, value)
379
+ }
380
+
381
+ private executeAdd(file: FileNode, command: any) {
382
+ const {itinerary, value} = command
383
+
384
+ const {content} = file
385
+ this.updater.executeAdd(content, itinerary, value)
386
+ }
387
+
388
+ private executeInsert(file: FileNode, command: any) {
389
+ const {itinerary, value} = command
390
+ if (itinerary === undefined) {
391
+ return
392
+ }
393
+
394
+ const {content} = file
395
+ this.updater.executeInsert(content, itinerary, value)
396
+ }
397
+
398
+ /**
399
+ * Executes a batch of commands, rebasing each on previous mutations.
400
+ */
401
+ public executeBatch(file: FileNode, command: any): void {
402
+ const { content } = file;
403
+ this.updater.executeBatch(content, command);
404
+ }
405
+
406
+ }
@@ -0,0 +1,105 @@
1
+ import { Itinerary, StackElement } from '@hamak/navigation-utils';
2
+
3
+ /**
4
+ * Base interface for structure node commands
5
+ */
6
+ export interface StructureNodeCommandBase {
7
+ name: "add-at" | "set-at" | "delete-at" | 'insert-at' | "batch-update"
8
+ }
9
+
10
+ /**
11
+ * Base interface for unitary (single operation) commands
12
+ */
13
+ export interface UnitaryStructureNodeCommandBase extends StructureNodeCommandBase {
14
+ name: "add-at" | "set-at" | "delete-at" | 'insert-at'
15
+ itinerary: Itinerary
16
+ }
17
+
18
+ /**
19
+ * Base interface for commands that insert/update values
20
+ */
21
+ export interface StructureNodeUpsertCommandBase extends UnitaryStructureNodeCommandBase{
22
+ name: "add-at" | "set-at" | 'insert-at'
23
+ prototypes? : StackElement<any>
24
+ }
25
+
26
+ /**
27
+ * Add a value at the specified itinerary
28
+ */
29
+ export interface AddStructureNodeCommand extends StructureNodeUpsertCommandBase {
30
+ name: "add-at"
31
+ value: any
32
+ }
33
+
34
+ /**
35
+ * Insert a value at the specified position
36
+ */
37
+ export interface InsertStructureNodeCommand extends StructureNodeUpsertCommandBase {
38
+ name: "insert-at"
39
+ value: any
40
+ }
41
+
42
+ /**
43
+ * Set a value at the specified itinerary
44
+ */
45
+ export interface SetStructureNodeCommand extends StructureNodeUpsertCommandBase {
46
+ name: "set-at"
47
+ value: any
48
+ }
49
+
50
+ /**
51
+ * Delete a value at the specified itinerary
52
+ */
53
+ export interface DeleteStructureNodeCommand extends UnitaryStructureNodeCommandBase {
54
+ name: "delete-at"
55
+ }
56
+
57
+ /**
58
+ * Batch update multiple operations
59
+ */
60
+ export interface BatchUpdateStructureNodeCommand extends StructureNodeCommandBase {
61
+ name: "batch-update"
62
+ autoRebase?: boolean
63
+ commands: UnitaryStructureNodeCommand[]
64
+ }
65
+
66
+ /**
67
+ * Union type for unitary structure node commands
68
+ */
69
+ export type UnitaryStructureNodeCommand =
70
+ | AddStructureNodeCommand
71
+ | InsertStructureNodeCommand
72
+ | SetStructureNodeCommand
73
+ | DeleteStructureNodeCommand
74
+
75
+ /**
76
+ * Union type for all structure node commands
77
+ */
78
+ export type StructureNodeCommand = UnitaryStructureNodeCommand | BatchUpdateStructureNodeCommand
79
+
80
+ /**
81
+ * Helper class for creating structure node commands
82
+ */
83
+ export class StructureNodeCommandHelper {
84
+ addNode(itinerary : Itinerary, value : any, prototypes?: StackElement<any>) : AddStructureNodeCommand{
85
+ return {name:'add-at', itinerary, value, prototypes}
86
+ }
87
+
88
+ insertNode(itinerary : Itinerary, value : any, prototypes?: StackElement<any>) : InsertStructureNodeCommand{
89
+ return {name:'insert-at', itinerary, value, prototypes}
90
+ }
91
+
92
+ setNode(itinerary : Itinerary, value : any, prototypes?: StackElement<any>) : SetStructureNodeCommand{
93
+ return {name:'set-at', itinerary, value, prototypes}
94
+ }
95
+
96
+ deleteNode(itinerary : Itinerary) : DeleteStructureNodeCommand{
97
+ return {name:'delete-at', itinerary}
98
+ }
99
+
100
+ batchUpdate(commands : UnitaryStructureNodeCommand[], autoRebase = false) : BatchUpdateStructureNodeCommand{
101
+ return {name:'batch-update', commands, autoRebase}
102
+ }
103
+ }
104
+
105
+ export const structs = new StructureNodeCommandHelper()
@@ -0,0 +1,180 @@
1
+ import { Action, createSelector } from '@reduxjs/toolkit';
2
+ import {
3
+ FileSystemCommand,
4
+ FileSystemCommandHandler,
5
+ pathSteps
6
+ } from '../commands/fs-commands';
7
+ import {
8
+ FileSystemNode,
9
+ fileSystemNodeInitialState,
10
+ FileSystemState,
11
+ FileContentSchema,
12
+ FileSystemNodeActionParams,
13
+ Selector
14
+ } from '@hamak/ui-store-api';
15
+ import { StructureNodeCommand } from '../commands/structure-commands';
16
+
17
+ /**
18
+ * Action interface for filesystem operations
19
+ */
20
+ export interface FileSystemNodeAction extends Action {
21
+ command: FileSystemCommand
22
+ }
23
+
24
+ /**
25
+ * Factory function to create a FileSystemAdapter
26
+ */
27
+ export function createFileSystemAdapter(sliceName: string) {
28
+ return new FileSystemAdapter(sliceName)
29
+ }
30
+
31
+ /**
32
+ * Filesystem reducer function type
33
+ */
34
+ export type FileSystemNodeReducerFn = (state: FileSystemState, action: Action) => FileSystemState
35
+
36
+ /**
37
+ * FileSystemAdapter - Manages Redux state for virtual filesystem
38
+ */
39
+ export class FileSystemAdapter {
40
+ readonly actions: FileSystemNodeActions
41
+ readonly commandHandler: FileSystemCommandHandler
42
+ readonly reducer: FileSystemNodeReducerFn
43
+
44
+ public constructor(public readonly sliceName: string) {
45
+ this.actions = new FileSystemNodeActions(sliceName)
46
+ this.commandHandler = new FileSystemCommandHandler()
47
+
48
+ this.reducer = (state= this.getInitialState(), action) => {
49
+ if (this.actions.isFileSystemNodeAction(action)) {
50
+ return this.commandHandler.execute(state, action.command)
51
+ }
52
+
53
+ return state
54
+ }
55
+ }
56
+
57
+ getInitialState(): FileSystemState {
58
+ return {root:{type: 'directory', name:'', children:{}, state: fileSystemNodeInitialState()}}
59
+ }
60
+
61
+ getActions() {
62
+ return this.actions
63
+ }
64
+
65
+ getReducer(extraReducers?: FileSystemNodeReducerFn): FileSystemNodeReducerFn {
66
+ if (extraReducers === undefined) {
67
+ return this.reducer
68
+ }
69
+
70
+ return (state, action) => this.reducer(extraReducers(state, action), action)
71
+ }
72
+
73
+ createSelector<S>(fileSystemSelector: Selector<S, FileSystemState | undefined>, path : string | string[]) : Selector<S, FileSystemNode | undefined>{
74
+ const rootSelector = createSelector(fileSystemSelector, fs => fs?.root)
75
+ const steps = pathSteps(path)
76
+ if(steps === undefined || steps.length === 0){
77
+ return rootSelector
78
+ }
79
+
80
+ return steps.reduce((acc, step) => {
81
+ return createSelector(acc, o => {
82
+ if(o === undefined || o.type === 'file'){
83
+ return o
84
+ }else {
85
+ return o.children[step]
86
+ }
87
+ })
88
+ }, rootSelector as Selector<S, FileSystemNode | undefined>)
89
+ }
90
+ }
91
+
92
+ /**
93
+ * FileSystemNodeActions - Action creators for filesystem operations
94
+ */
95
+ export class FileSystemNodeActions {
96
+ private readonly _mkdirType: string;
97
+ private readonly _setFileType: string;
98
+ private readonly _removeType: string;
99
+ private readonly _updateFileContentType: string;
100
+ private readonly _setFileContentType: string;
101
+ private actionTypeSet: Set<string>
102
+
103
+ constructor(public sliceName: string) {
104
+ this._mkdirType = `${this.sliceName}/createDirectoryNode`
105
+ this._setFileType = `${this.sliceName}/createFileNode`
106
+ this._removeType = `${this.sliceName}/removeNode`
107
+ this._updateFileContentType = `${this.sliceName}/updateFileContent`
108
+ this._setFileContentType = `${this.sliceName}/setFileContent`
109
+
110
+ this.actionTypeSet = new Set([
111
+ this._mkdirType,
112
+ this._setFileType,
113
+ this._removeType,
114
+ this._updateFileContentType,
115
+ this._setFileContentType
116
+ ])
117
+ }
118
+
119
+ get mkdirType(): string {
120
+ return this._mkdirType;
121
+ }
122
+
123
+ get setFileType(): string {
124
+ return this._setFileType;
125
+ }
126
+
127
+ get removeType(): string {
128
+ return this._removeType;
129
+ }
130
+
131
+ get updateFileContentType(): string {
132
+ return this._updateFileContentType;
133
+ }
134
+
135
+ get setFileContentType(): string {
136
+ return this._setFileContentType;
137
+ }
138
+
139
+ isFileSystemNodeAction(action: Action): action is FileSystemNodeAction {
140
+ return this.actionTypeSet.has(action.type)
141
+ }
142
+
143
+ public mkdir(path: string | string[], parents?:boolean): FileSystemNodeAction {
144
+ return {
145
+ type: this.mkdirType,
146
+ command: {name : 'mkdir', path, parents}
147
+ }
148
+ }
149
+
150
+ public setFile(path: string | string[], content:any, schema : FileContentSchema, params : FileSystemNodeActionParams = {override: true, contentIsPresent:true}): FileSystemNodeAction {
151
+ const {override, contentIsPresent} = params
152
+ return {
153
+ type: this.setFileType,
154
+ command: {name: 'set-file', path, content, schema, override, contentIsPresent}
155
+ }
156
+ }
157
+
158
+ public updateFileContent(path: string | string[], contentCommand : StructureNodeCommand ): FileSystemNodeAction {
159
+ return {
160
+ type: this.updateFileContentType,
161
+ command: {name: 'update-file-content', path, contentCommand}
162
+ }
163
+ }
164
+
165
+ public setFileContent(path: string | string[], content : any, fromRemote = false): FileSystemNodeAction {
166
+ return {
167
+ type: this.setFileContentType,
168
+ command: {name: 'set-file-content', path, content, fromRemote}
169
+ }
170
+ }
171
+
172
+
173
+ public removeNode(path : string | string[], recursive? : boolean): FileSystemNodeAction {
174
+ return {
175
+ type: this.removeType,
176
+ command: {name: 'remove', path, recursive}
177
+ }
178
+ }
179
+
180
+ }