diff --git a/src/storage/common_storage.ts b/src/storage/common_storage.ts index 1afe4a22..5a0cc424 100644 --- a/src/storage/common_storage.ts +++ b/src/storage/common_storage.ts @@ -32,6 +32,8 @@ import { createGeneratorContext } from '../editor/generator_context'; // Types, constants, and functions related to modules, regardless of where the modules are stored. +export const CURRENT_VERSION = '0.1'; + export type Module = { modulePath: string, moduleType: string, @@ -90,11 +92,13 @@ const MARKER_BLOCKS_CONTENT = 'blocksContent: '; const MARKER_METHODS = 'methods: '; const MARKER_MODULE_TYPE = 'moduleType: '; const MARKER_COMPONENTS = 'components: '; +const MARKER_VERSION = 'version: '; const PARTS_INDEX_BLOCKS_CONTENT = 0; const PARTS_INDEX_METHODS = 1; const PARTS_INDEX_MODULE_TYPE = 2; const PARTS_INDEX_COMPONENTS = 3; -const NUMBER_OF_PARTS = 4; +const PARTS_INDEX_VERSION = 4; +const NUMBER_OF_PARTS = 5; export const UPLOAD_DOWNLOAD_FILE_EXTENSION = '.blocks'; @@ -572,12 +576,17 @@ export function makeModuleContent( pythonCode: string, blocksContent: string, methodsContent: string, - componentsContent: string): string { + componentsContent: string, + optVersionContent?: string): string { + + const versionContent = optVersionContent ? optVersionContent : CURRENT_VERSION; + let delimiter = DELIMITER_PREFIX; while (module.moduleType.includes(delimiter) || blocksContent.includes(delimiter) || methodsContent.includes(delimiter) - || componentsContent.includes(delimiter)) { + || componentsContent.includes(delimiter) + || versionContent.includes(delimiter)) { delimiter += '.'; } return ( @@ -585,6 +594,8 @@ export function makeModuleContent( pythonCode + '\n\n\n' + '"""\n' + delimiter + '\n' + + MARKER_VERSION + versionContent + '\n' + + delimiter + '\n' + MARKER_COMPONENTS + componentsContent + '\n' + delimiter + '\n' + MARKER_MODULE_TYPE + module.moduleType + '\n' + @@ -639,6 +650,10 @@ function getParts(moduleContent: string): string[] { // This module was saved without components. parts.push(MARKER_COMPONENTS + '[]'); } + if (parts.length <= PARTS_INDEX_VERSION) { + // This module was saved without version. + parts.push(MARKER_VERSION + '0.0'); + } return parts; } @@ -692,6 +707,18 @@ export function extractComponents(moduleContent: string): Component[] { return components; } +/** + * Extract the version from the given module content. + */ +export function extractVersion(moduleContent: string): string { + const parts = getParts(moduleContent); + let versionContent = parts[PARTS_INDEX_VERSION]; + if (versionContent.startsWith(MARKER_VERSION)) { + versionContent = versionContent.substring(MARKER_VERSION.length); + } + return versionContent; +} + /** * Produce the blob for downloading a project. */ @@ -737,6 +764,10 @@ function _processModuleContentForDownload( if (componentsContent.startsWith(MARKER_COMPONENTS)) { componentsContent = componentsContent.substring(MARKER_COMPONENTS.length); } + let versionContent = parts[PARTS_INDEX_VERSION]; + if (versionContent.startsWith(MARKER_VERSION)) { + versionContent = versionContent.substring(MARKER_VERSION.length); + } const module: Module = { modulePath: makeModulePath(projectName, moduleName), @@ -750,7 +781,12 @@ function _processModuleContentForDownload( // Clear out the python content. const pythonCode = ''; return makeModuleContent( - module, pythonCode, blocksContent, methodsContent, componentsContent); + module, + pythonCode, + blocksContent, + methodsContent, + componentsContent, + versionContent); } /** @@ -826,6 +862,10 @@ export function _processUploadedModule( projectName: string, filename: string, uploadedContent: string) : [string, string, string] { const parts = getParts(uploadedContent); + let versionContent = parts[PARTS_INDEX_VERSION]; + if (versionContent.startsWith(MARKER_VERSION)) { + versionContent = versionContent.substring(MARKER_VERSION.length); + } let blocksContent = parts[PARTS_INDEX_BLOCKS_CONTENT]; if (blocksContent.startsWith(MARKER_BLOCKS_CONTENT)) { blocksContent = blocksContent.substring(MARKER_BLOCKS_CONTENT.length); @@ -869,6 +909,11 @@ export function _processUploadedModule( headlessBlocklyWorkspace, generatorContext); const moduleContent = makeModuleContent( - module, pythonCode, blocksContent, methodsContent, componentsContent); + module, + pythonCode, + blocksContent, + methodsContent, + componentsContent, + versionContent); return [moduleName, moduleType, moduleContent]; }