Skip to content

Commit 5a5408b

Browse files
committed
Fixed download and upload code.
1 parent 951693e commit 5a5408b

File tree

3 files changed

+74
-53
lines changed

3 files changed

+74
-53
lines changed

src/storage/module.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,11 @@ export type Robot = Module;
4040
export type Mechanism = Module;
4141
export type OpMode = Module;
4242

43+
44+
export function stringToModuleType(str: string): ModuleType {
45+
const moduleType = Object.values(ModuleType).find((value) => value == str);
46+
if (moduleType) {
47+
return moduleType;
48+
}
49+
throw new Error('Unable to convert string "' + str + '" to module type.');
50+
}

src/storage/names.ts

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ export const UPLOAD_DOWNLOAD_FILE_EXTENSION = '.blocks';
3030

3131
const REGEX_PROJECT_NAME_PART = '[A-Z][A-Za-z0-9]*';
3232
const REGEX_CLASS_NAME_PART = '[A-Z][A-Za-z0-9]*';
33-
const REGEX_MODULE_TYPE = '\.(robot|mechanism|opmode)';
33+
const REGEX_MODULE_TYPE_PART = '\.(robot|mechanism|opmode)';
3434
const REGEX_MODULE_PATH = '^(' + REGEX_PROJECT_NAME_PART + ')/(' + REGEX_CLASS_NAME_PART + ')' +
35-
REGEX_MODULE_TYPE + escapeRegExp(JSON_FILE_EXTENSION) + '$';
35+
REGEX_MODULE_TYPE_PART + escapeRegExp(JSON_FILE_EXTENSION) + '$';
36+
const REGEX_MODULE_PATH_TO_FILE_NAME = '^' + REGEX_PROJECT_NAME_PART + '/(' + REGEX_CLASS_NAME_PART +
37+
REGEX_MODULE_TYPE_PART + escapeRegExp(JSON_FILE_EXTENSION) + ')$';
38+
const REGEX_FILE_NAME = '^(' + REGEX_CLASS_NAME_PART + ')' +
39+
REGEX_MODULE_TYPE_PART + escapeRegExp(JSON_FILE_EXTENSION) + '$';
3640

3741
/**
3842
* Returns true if the given name is a valid class name.
@@ -84,7 +88,7 @@ export function snakeCaseToPascalCase(snakeCaseName: string): string {
8488
*/
8589
export function makeModulePathRegexPattern(projectName: string): string {
8690
return '^' + escapeRegExp(projectName) + '/' + REGEX_CLASS_NAME_PART +
87-
REGEX_MODULE_TYPE + escapeRegExp(JSON_FILE_EXTENSION) + '$';
91+
REGEX_MODULE_TYPE_PART + escapeRegExp(JSON_FILE_EXTENSION) + '$';
8892
}
8993

9094
function escapeRegExp(text: string): string {
@@ -107,7 +111,7 @@ export function makeRobotPath(projectName: string): string {
107111
}
108112

109113
/**
110-
* Returns the project path for given module path.
114+
* Returns the project name for given module path.
111115
*/
112116
export function getProjectName(modulePath: string): string {
113117
const regex = new RegExp(REGEX_MODULE_PATH);
@@ -119,34 +123,49 @@ export function getProjectName(modulePath: string): string {
119123
}
120124

121125
/**
122-
* Returns the class name for given module path.
126+
* Returns the file name for given module path.
123127
*/
124-
export function getClassName(modulePath: string): string {
125-
const regex = new RegExp(REGEX_MODULE_PATH);
128+
export function getFileName(modulePath: string): string {
129+
const regex = new RegExp(REGEX_MODULE_PATH_TO_FILE_NAME);
126130
const result = regex.exec(modulePath)
127131
if (!result) {
128-
throw new Error('Unable to extract the class name from "' + modulePath + '"');
132+
throw new Error('Unable to extract the project name from "' + modulePath + '"');
129133
}
130-
return result[2];
134+
return result[1];
131135
}
132136

133137
/**
134-
* Returns the module type for given module path.
138+
* Returns the class name for given module path or file name.
135139
*/
136-
export function getModuleType(modulePath: string): storageModule.ModuleType {
137-
const regex = new RegExp(REGEX_MODULE_PATH);
138-
const result = regex.exec(modulePath)
139-
if (!result) {
140-
throw new Error('Unable to extract the module type from "' + modulePath + '"');
140+
export function getClassName(modulePathOrFileName: string): string {
141+
let regex = new RegExp(REGEX_MODULE_PATH);
142+
let result = regex.exec(modulePathOrFileName);
143+
if (result) {
144+
return result[2];
141145
}
142-
143-
const str = result[2];
144-
const moduleType = storageModule.ModuleType[str as keyof typeof storageModule.ModuleType];
145-
if (!Object.values(storageModule.ModuleType).includes(moduleType)) {
146-
throw new Error('Unable to extract the module type from "' + modulePath + '"');
146+
regex = new RegExp(REGEX_FILE_NAME);
147+
result = regex.exec(modulePathOrFileName);
148+
if (result) {
149+
return result[1];
147150
}
151+
throw new Error('Unable to extract the class name from "' + modulePathOrFileName + '"');
152+
}
148153

149-
return moduleType;
154+
/**
155+
* Returns the module type for given module path or file name.
156+
*/
157+
export function getModuleType(modulePathOrFileName: string): storageModule.ModuleType {
158+
let regex = new RegExp(REGEX_MODULE_PATH);
159+
let result = regex.exec(modulePathOrFileName);
160+
if (result) {
161+
return storageModule.stringToModuleType(result[3]);
162+
}
163+
regex = new RegExp(REGEX_FILE_NAME);
164+
result = regex.exec(modulePathOrFileName);
165+
if (result) {
166+
return storageModule.stringToModuleType(result[2]);
167+
}
168+
throw new Error('Unable to extract the module type from "' + modulePathOrFileName + '"');
150169
}
151170

152171
/**

src/storage/project.ts

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ async function renameOrCopyProject(
171171

172172
for (const modulePath in pathToModuleContent) {
173173
const className = storageNames.getClassName(modulePath);
174-
const moduleType = pathToModuleContent[modulePath].getModuleType()
174+
const moduleType = storageNames.getModuleType(modulePath);
175175
const newModulePath = storageNames.makeModulePath(newProjectName, className, moduleType);
176176
const moduleContentText = pathToModuleContent[modulePath].getModuleContentText();
177177
await storage.saveModule(newModulePath, moduleContentText);
@@ -424,18 +424,17 @@ export async function downloadProject(
424424
const pathToModuleContent = await storage.listModules(
425425
storageNames.makeModulePathRegexPattern(project.projectName));
426426

427-
const classNameToModuleContentText: {[className: string]: string} = {}; // value is module content text
427+
const fileNameToModuleContentText: {[fileName: string]: string} = {}; // value is module content text
428428
for (const modulePath in pathToModuleContent) {
429-
const className = storageNames.getClassName(modulePath);
429+
const fileName = storageNames.getFileName(modulePath);
430430
const moduleContentText = pathToModuleContent[modulePath].getModuleContentText();
431-
classNameToModuleContentText[className] = moduleContentText;
431+
fileNameToModuleContentText[fileName] = moduleContentText;
432432
}
433433

434434
const zip = new JSZip();
435-
for (const className in classNameToModuleContentText) {
436-
const moduleContentText = classNameToModuleContentText[className];
437-
const filename = className + storageNames.JSON_FILE_EXTENSION;
438-
zip.file(filename, moduleContentText);
435+
for (const fileName in fileNameToModuleContentText) {
436+
const moduleContentText = fileNameToModuleContentText[fileName];
437+
zip.file(fileName, moduleContentText);
439438
}
440439
const content = await zip.generateAsync({ type: "blob" });
441440
return URL.createObjectURL(content);
@@ -453,15 +452,14 @@ export function makeUploadProjectName(
453452

454453
export async function uploadProject(
455454
storage: commonStorage.Storage, projectName: string, blobUrl: string): Promise<void> {
456-
// Process the uploaded blob to get the module types and contents.
457-
const classNameToModuleContentText: { [className: string]: string } = {}; // value is module content text.
458-
const classNameToModuleType: { [className: string]: storageModule.ModuleType } = {};
459-
await processUploadedBlob(blobUrl, classNameToModuleContentText, classNameToModuleType);
455+
// Process the uploaded blob to get the file names and contents.
456+
const fileNameToModuleContentText = await processUploadedBlob(blobUrl);
460457

461458
// Save each module.
462-
for (const className in classNameToModuleContentText) {
463-
const moduleContentText = classNameToModuleContentText[className];
464-
const moduleType = classNameToModuleType[className];
459+
for (const fileName in fileNameToModuleContentText) {
460+
const moduleContentText = fileNameToModuleContentText[fileName];
461+
const className = storageNames.getClassName(fileName);
462+
const moduleType = storageNames.getModuleType(fileName);
465463
const modulePath = storageNames.makeModulePath(projectName, className, moduleType);
466464
await storage.saveModule(modulePath, moduleContentText);
467465
}
@@ -470,10 +468,7 @@ export async function uploadProject(
470468
/**
471469
* Process the uploaded blob to get the module class names and contents.
472470
*/
473-
async function processUploadedBlob(
474-
blobUrl: string,
475-
classNameToModuleContentText: { [className: string]: string }, // value is module content text.
476-
classNameToModuleType: { [className: string]: storageModule.ModuleType }): Promise<void> {
471+
async function processUploadedBlob(blobUrl: string): Promise<{ [className: string]: string }> {
477472

478473
const prefix = 'data:application/octet-stream;base64,';
479474
if (!blobUrl.startsWith(prefix)) {
@@ -483,35 +478,34 @@ async function processUploadedBlob(
483478

484479
const zip = await JSZip.loadAsync(data, { base64: true });
485480
const promises: { [key: string]: Promise<string> } = {};
486-
zip.forEach((filename, zipEntry) => {
487-
const className = filename.endsWith(storageNames.JSON_FILE_EXTENSION)
488-
? filename.substring(0, filename.length - storageNames.JSON_FILE_EXTENSION.length)
489-
: filename;
490-
promises[className] = zipEntry.async('text');
481+
zip.forEach((fileName, zipEntry) => {
482+
promises[fileName] = zipEntry.async('text');
491483
});
492484

493485
// Wait for all promises to resolve.
494486
const files: { [fileName: string]: string } = {}; // value is file content
495487
await Promise.all(
496-
Object.entries(promises).map(async ([filename, promise]) => {
497-
files[filename] = await promise;
488+
Object.entries(promises).map(async ([fileName, promise]) => {
489+
files[fileName] = await promise;
498490
})
499491
);
500492

501493
// Process each module's content.
502494
let foundRobot = false;
503-
for (const filename in files) {
504-
const className = filename;
505-
if (className === storageNames.CLASS_NAME_ROBOT) {
495+
const fileNameToModuleContentText: { [fileName: string]: string } = {}; // value is module content text
496+
for (const fileName in files) {
497+
const moduleType = storageNames.getModuleType(fileName);
498+
if (moduleType === storageModule.ModuleType.ROBOT) {
506499
foundRobot = true;
507500
}
508501
// Make sure we can parse the content.
509-
const moduleContent = storageModuleContent.parseModuleContentText(files[filename]);
510-
classNameToModuleContentText[className] = moduleContent.getModuleContentText();
511-
classNameToModuleType[className] = moduleContent.getModuleType();
502+
const moduleContent = storageModuleContent.parseModuleContentText(files[fileName]);
503+
fileNameToModuleContentText[fileName] = moduleContent.getModuleContentText();
512504
}
513505

514506
if (!foundRobot) {
515507
throw new Error('Uploaded file did not contain a Robot.');
516508
}
509+
510+
return fileNameToModuleContentText;
517511
}

0 commit comments

Comments
 (0)