Skip to content

Commit 5976346

Browse files
committed
Fixed import logic to support cloud files
1 parent 487159f commit 5976346

File tree

8 files changed

+87
-70
lines changed

8 files changed

+87
-70
lines changed

.eslintrc.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"unicorn/no-array-for-each": "off",
1919
"unicorn/prefer-object-from-entries": "off",
2020
"unicorn/prefer-type-error": "off",
21+
"unicorn/no-static-only-class": "off",
22+
"@typescript-eslint/no-duplicate-enum-values": "off",
2123
"quotes": [
2224
"error",
2325
"single"

src/api/dashboard/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,14 @@ export const DashboardApiClient = {
4040
// }
4141

4242
return '1b80818e-5304-4158-80a3-82e17ff2c79e';
43+
},
44+
45+
async saveDocumentUpdate(id: string, contents: string): Promise<void> {
46+
const login = LoginHelper.get()?.credentials;
47+
if (!login) {
48+
throw new Error('Not logged in');
49+
}
50+
51+
4352
}
4453
}

src/entities/project.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { PlanRequestData, ResourceOperation, ValidateResponseData } from 'codify-schemas';
2+
import { validate } from 'uuid'
23

34
import { PluginValidationError, PluginValidationErrorParams, TypeNotFoundError } from '../common/errors.js';
45
import { ctx } from '../events/context.js';
@@ -60,6 +61,11 @@ ${JSON.stringify(projectConfigs, null, 2)}`);
6061
return this.stateConfigs !== null && this.stateConfigs !== undefined && this.stateConfigs.length > 0;
6162
}
6263

64+
// TODO: Update to a more robust method in the future
65+
isCloud(): boolean {
66+
return validate(this.codifyFiles[0])
67+
}
68+
6369
filter(ids: string[]): Project {
6470
this.resourceConfigs = this.resourceConfigs.filter((r) => ids.find((id) => r.id.includes(id)));
6571
this.stateConfigs = this.stateConfigs?.filter((s) => ids.includes(s.id)) ?? null;

src/utils/file-modification-calculator.ts renamed to src/generators/file-modification-calculator.ts

Lines changed: 25 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,24 @@
1-
import { ResourceConfig } from '../entities/resource-config.js';
2-
3-
import * as jsonSourceMap from 'json-source-map';
1+
import detectIndent from 'detect-indent';
42
import jju from 'jju'
53

6-
import { FileType, InMemoryFile } from '../parser/entities.js';
7-
import { SourceMap, SourceMapCache } from '../parser/source-maps.js';
8-
import detectIndent from 'detect-indent';
94
import { Project } from '../entities/project.js';
105
import { ProjectConfig } from '../entities/project-config.js';
6+
import { ResourceConfig } from '../entities/resource-config.js';
7+
import { FileType, InMemoryFile } from '../parser/entities.js';
8+
import { SourceMap } from '../parser/source-maps.js';
119
import { prettyFormatFileDiff } from '../ui/file-diff-pretty-printer.js';
12-
import { deepEqual } from './index.js';
13-
14-
export enum ModificationType {
15-
INSERT_OR_UPDATE,
16-
DELETE
17-
}
18-
19-
export interface ModifiedResource {
20-
resource: ResourceConfig;
21-
modification: ModificationType
22-
}
23-
24-
export interface FileModificationResult {
25-
newFile: string;
26-
diff: string;
27-
}
10+
import { deepEqual } from '../utils/index.js';
11+
import { FileModificationResult, ModificationType, ModifiedResource } from './index.js';
2812

2913
export class FileModificationCalculator {
30-
private existingFile: InMemoryFile;
14+
private readonly existingFile: InMemoryFile;
3115
private existingConfigs: ResourceConfig[];
32-
private sourceMap: SourceMap;
16+
private readonly sourceMap: SourceMap;
3317
private totalConfigLength: number;
34-
private indentString: string;
18+
private readonly indentString: string;
3519

3620
constructor(existing: Project) {
37-
const { file, sourceMap } = existing.sourceMaps?.getSourceMap(existing.codifyFiles[0])!;
21+
const { file, sourceMap } = existing.sourceMaps!.getSourceMap(existing.codifyFiles[0])!;
3822
this.existingFile = file;
3923
this.sourceMap = sourceMap;
4024
this.existingConfigs = [...existing.resourceConfigs];
@@ -69,12 +53,11 @@ export class FileModificationCalculator {
6953
continue;
7054
}
7155

72-
const duplicateSourceKey = existing.sourceMapKey?.split('#').at(1)!;
73-
const sourceIndex = Number.parseInt(duplicateSourceKey.split('/').at(1)!)
74-
const isOnly = this.totalConfigLength === 1;
56+
const duplicateSourceKey = existing.sourceMapKey!.split('#').at(1)!;
57+
const sourceIndex = Number.parseInt(duplicateSourceKey.split('/').at(1)!, 10)
7558

7659
if (modified.modification === ModificationType.DELETE) {
77-
newFile = this.remove(newFile, this.sourceMap, sourceIndex, isOnly);
60+
newFile = this.remove(newFile, sourceIndex);
7861
this.totalConfigLength -= 1;
7962

8063
continue;
@@ -99,7 +82,7 @@ export class FileModificationCalculator {
9982
}
10083

10184
return {
102-
newFile: newFile,
85+
newFile,
10386
diff: prettyFormatFileDiff(this.existingFile.contents, newFile),
10487
}
10588
}
@@ -110,7 +93,7 @@ export class FileModificationCalculator {
11093
return;
11194
}
11295

113-
if (this.existingFile?.fileType !== FileType.JSON && this.existingFile?.fileType !== FileType.JSON5 && this.existingFile?.fileType !== FileType.JSONC) {
96+
if (this.existingFile?.fileType !== FileType.JSON && this.existingFile?.fileType !== FileType.JSON5 && this.existingFile?.fileType !== FileType.JSONC && this.existingFile?.fileType !== FileType.CLOUD) {
11497
throw new Error(`Only updating .json, .json5, and .jsonc files are currently supported. Found ${this.existingFile?.filePath}`);
11598
}
11699

@@ -167,9 +150,7 @@ export class FileModificationCalculator {
167150

168151
private remove(
169152
file: string,
170-
sourceMap: SourceMap,
171153
sourceIndex: number,
172-
isOnly: boolean,
173154
): string {
174155
const isLast = sourceIndex === this.totalConfigLength - 1;
175156
const isFirst = sourceIndex === 0;
@@ -200,42 +181,18 @@ export class FileModificationCalculator {
200181
): string {
201182
// Updates: for now let's remove and re-add the entire object. Only two formatting availalbe either same line or multi-line
202183
const { value, valueEnd } = this.sourceMap.lookup(`/${sourceIndex}`)!;
203-
const isFirst = sourceIndex === 0;
204184
const sortedResource = this.sortKeys(resource.raw, existing.raw);
205185

206-
let content = jju.update(file.slice(value.position, valueEnd.position), sortedResource)
207-
return this.splice(file, value?.position!, valueEnd.position - value.position, content);
208-
}
209-
210-
/** Attempt to make arrays and objects oneliners if they were before. It does this by creating a new source map */
211-
private updateParamsToOnelineIfNeeded(content: string, sourceMap: SourceMap, sourceIndex: number): string {
212-
// Attempt to make arrays and objects oneliners if they were before. It does this by creating a new source map
213-
const parsedContent = JSON.parse(content);
214-
const parsedPointers = jsonSourceMap.parse(content);
215-
const parsedSourceMap = new SourceMapCache()
216-
parsedSourceMap.addSourceMap({ filePath: '', fileType: FileType.JSON, contents: parsedContent }, parsedPointers);
217-
218-
for (const [key, value] of Object.entries(parsedContent)) {
219-
const source = sourceMap.lookup(`/${sourceIndex}/${key}`);
220-
if ((Array.isArray(value) || typeof value === 'object') && source && source.value.line === source.valueEnd.line) {
221-
const { value, valueEnd } = parsedSourceMap.lookup(`#/${key}`)!
222-
content = this.splice(
223-
content,
224-
value.position, valueEnd.position - value.position,
225-
JSON.stringify(parsedContent[key]).replaceAll('\n', '').replaceAll(/}$/g, ' }')
226-
)
227-
}
228-
}
229-
230-
return content;
186+
const content = jju.update(file.slice(value.position, valueEnd.position), sortedResource)
187+
return this.splice(file, value.position!, valueEnd.position - value.position, content);
231188
}
232189

233190
private splice(s: string, start: number, deleteCount = 0, insert = '') {
234-
return s.substring(0, start) + insert + s.substring(start + deleteCount);
191+
return s.slice(0, start) + insert + s.slice(start + deleteCount);
235192
}
236193

237194
private removeSlice(s: string, start: number, end: number) {
238-
return s.substring(0, start) + s.substring(end);
195+
return s.slice(0, start) + s.slice(end);
239196
}
240197

241198
private isResourceConfig(config: ProjectConfig | ResourceConfig): config is ResourceConfig {
@@ -244,7 +201,7 @@ export class FileModificationCalculator {
244201

245202
private sortKeys(obj: Record<string, unknown>, referenceOrder?: Record<string, unknown>): Record<string, unknown> {
246203
const reference = Object.keys(referenceOrder
247-
?? Object.fromEntries([...Object.keys(obj)].sort().map((k) => [k, undefined]))
204+
?? Object.fromEntries(Object.keys(obj).sort().map((k) => [k, undefined]))
248205
);
249206

250207
return Object.fromEntries(
@@ -262,7 +219,7 @@ export class FileModificationCalculator {
262219
)
263220
}
264221

265-
private fileTypeString(fileType: FileType): 'json' | 'json5' | 'cjson' {
222+
private fileTypeString(fileType: FileType): 'cjson' | 'json' | 'json5' {
266223
if (fileType === FileType.JSON) {
267224
return 'json'
268225
}
@@ -275,6 +232,10 @@ export class FileModificationCalculator {
275232
return 'cjson'
276233
}
277234

235+
if (fileType === FileType.CLOUD) {
236+
return 'cjson'
237+
}
238+
278239
throw new Error(`Unsupported file type ${fileType} when trying to generate new configs`);
279240
}
280241
}

src/generators/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ResourceConfig } from '../entities/resource-config.js';
2+
3+
export enum ModificationType {
4+
INSERT_OR_UPDATE,
5+
DELETE
6+
}
7+
8+
export interface ModifiedResource {
9+
resource: ResourceConfig;
10+
modification: ModificationType
11+
}
12+
13+
export interface FileModificationResult {
14+
newFile: string;
15+
diff: string;
16+
}

src/generators/writer.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { validate } from 'uuid'
2+
3+
import { DashboardApiClient } from '../api/dashboard/index.js';
4+
import { FileUtils } from '../utils/file.js';
5+
6+
export class FileUpdater {
7+
static async write(filePath: string, content: string) {
8+
// Cloud file
9+
if (validate(filePath)) {
10+
return DashboardApiClient.saveDocumentUpdate(filePath, content);
11+
}
12+
13+
return FileUtils.writeFile(filePath, content);
14+
}
15+
16+
}

src/orchestrators/import.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import { Project } from '../entities/project.js';
55
import { ResourceConfig } from '../entities/resource-config.js';
66
import { ResourceInfo } from '../entities/resource-info.js';
77
import { ProcessName, SubProcessName, ctx } from '../events/context.js';
8+
import { FileModificationCalculator } from '../generators/file-modification-calculator.js';
9+
import { ModificationType } from '../generators/index.js';
10+
import { FileUpdater } from '../generators/writer.js';
811
import { CodifyParser } from '../parser/index.js';
912
import { DependencyMap, PluginManager } from '../plugins/plugin-manager.js';
1013
import { prettyFormatFileDiff } from '../ui/file-diff-pretty-printer.js';
1114
import { PromptType, Reporter } from '../ui/reporters/reporter.js';
1215
import { FileUtils } from '../utils/file.js';
13-
import { FileModificationCalculator, ModificationType } from '../utils/file-modification-calculator.js';
1416
import { groupBy, sleep } from '../utils/index.js';
1517
import { wildCardMatch } from '../utils/wild-card-match.js';
1618

@@ -308,7 +310,7 @@ ${JSON.stringify(unsupportedTypeIds)}`);
308310
}
309311

310312
for (const diff of diffs) {
311-
await FileUtils.writeFile(diff.file, diff.modification.newFile);
313+
await FileUpdater.write(diff.file, diff.modification.newFile);
312314
}
313315

314316
reporter.displayMessage('\n🎉 Imported completed and saved to file 🎉');
@@ -332,7 +334,7 @@ ${JSON.stringify(unsupportedTypeIds)}`);
332334
return;
333335
}
334336

335-
await FileUtils.writeFile(filePath, newFile);
337+
await FileUpdater.write(filePath, newFile);
336338

337339
reporter.displayMessage('\n🎉 Imported completed and saved to file 🎉');
338340

src/parser/cloud/cloud-parser.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Config } from 'codify-schemas';
2+
import jsonSourceMap from 'json-source-map';
23

34
import { InMemoryFile, LanguageSpecificParser, ParsedConfig } from '../entities.js';
45
import { SourceMapCache } from '../source-maps.js';
@@ -7,11 +8,15 @@ export class CloudParser implements LanguageSpecificParser {
78
parse(file: InMemoryFile, sourceMaps: SourceMapCache): ParsedConfig[] {
89
const contents = JSON.parse(file.contents) as Array<Config>;
910

10-
return contents.map((content) => {
11-
const { id, type, ...config } = content;
11+
if (sourceMaps) {
12+
sourceMaps.addSourceMap(file, jsonSourceMap.parse(file.contents));
13+
}
14+
15+
return contents.map((content, idx) => {
16+
const { type, ...config } = content;
1217
return {
1318
contents: { type, ...config },
14-
sourceMapKey: id as string,
19+
sourceMapKey: SourceMapCache.constructKey(file.filePath, `/${idx}`),
1520
}
1621
})
1722
}

0 commit comments

Comments
 (0)