@hamak/ui-store-impl 0.3.0 → 0.4.1

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