UNPKG

aia-kit

Version:

Read, Parse, Edit, Write, Analyze AIA/AIX/AIS files.

191 lines 7.35 kB
/** * Defines functions used to extract components, extensions, and assets from * an AIA file. * * * @file This file defines the AIAReader class. * @author vishwas@kodular.io (Vishwas Adiga) * @since 1.0.0 * @license */ import { BlobReader, HttpReader, ZipReader } from "@zip.js/zip.js"; import { Project } from './project.js'; import { Screen } from "./screen.js"; import { Extension } from "./extension.js"; import { Asset } from "./asset.js"; import { getFileInfo, readProjectProperties } from "./utils/utils.js"; import { getBlobFileContent, getTextFileContent } from "./utils/zipjs.js"; import { AiaFileStructure } from "./file_structures.js"; /** * Class that reads/parses an AIA file. * * @since 1.0.0 * @access public */ export class AIAReader { /** * Unzips and reads every file in an AIA and then parses it. * * @since 1.0.0 * @access public * * @param {Blob | String} fileOrUrl The AIA file, or a URL pointing to it. * * @return {Promise} A Promise object, when resolved, yields the parsed * AIProject object. */ static async parse(fileOrUrl) { const readerObj = fileOrUrl instanceof Blob ? new BlobReader(fileOrUrl) : new HttpReader(fileOrUrl); const zr = new ZipReader(readerObj); const entries = await zr.getEntries(); let projectPropertiesFile = entries.find(x => x.filename === AiaFileStructure.projectProperties); if (!projectPropertiesFile) { throw new Error('Invalid AIA file: project.properties not found'); } const projectProperties = await readProjectProperties(projectPropertiesFile); const project = Project.from(projectProperties); // Extensions are loaded first so that instances of extensions can // later fetch the correct descriptor JSON files. for (let extension of await this.generateExtensions(entries.filter(x => getFileInfo(x)[1] === 'json'))) { project.addExtension(extension); } // Screens are loaded asynchronously. for (let screen of await this.generateScreens(entries.filter(x => getFileInfo(x)[1] === 'scm' || getFileInfo(x)[1] === 'bky'))) { project.addScreen(screen); } // Finally, all the assets are loaded. for (let asset of await this.generateAssets(entries.filter(x => x.filename.split('/')[0] === 'assets' && x.filename.split('/')[2] === undefined))) { project.addAsset(asset); } return project; } /** * Asynchronously reads every screen in the project. * * @since 1.0.0 * @access private * * @class * @param {Array} files An array of files that have a filetype .scm or .bky. * @return {Promise<Screen>} A Promise object, when resolved, yields the parsed * */ static async generateScreens(files) { const schemes = []; const blocks = []; // First, we load all the scheme files into the schemes array and the Blockly // files into the blocks array. for (let file of files) { const content = await getTextFileContent(file); let [fileName, fileType] = getFileInfo(file); if (fileType === 'scm') { schemes.push({ name: fileName, scm: content }); } else if (fileType === 'bky') { blocks.push({ name: fileName, bky: content }); } } const screens = []; // Then, for each scheme file, we create a new AIScreen and initialise it with // the corresponding Blockly file. for (let scheme of schemes) { let block = blocks.find(x => x.name === scheme.name); if (!block) continue; screens.push(Screen.init(scheme.name, scheme.scm, block.bky)); } return Promise.all(screens); } /** * Asynchronously reads every extension used in the project. * * @since 1.0.0 * @access private * * @class * @param {Array} files An array of files that have a filetype .json. * * @return {Promise<Array>} An array of AIExtension objects for the project being read. */ static async generateExtensions(files) { const buildInfos = []; const descriptors = []; // The component_build_info and component descriptor files are being read. // Some extensions describe the component as a JSON array, while some as a // JSON object. We collect both files at the same time and handle them // separately later. for (let file of files) { const content = await getTextFileContent(file); let fileName = getFileInfo(file)[0]; let extName = file.filename.split('/')[2]; if (fileName === 'component_build_infos') { buildInfos.push({ name: extName, info: JSON.parse(content) }); } else if (fileName === 'component_build_info') { buildInfos.push({ name: extName, info: [JSON.parse(content)] }); } else if (fileName === 'components') { descriptors.push({ name: extName, descriptor: JSON.parse(content) }); } else if (fileName === 'component') { descriptors.push({ name: extName, descriptor: [JSON.parse(content)] }); } } const extensions = []; // If the build info is an array, then the extension is a pack // (a collection of extensions bundled into one file). In such a case, we // iterate through each element in the array and create a new AIExtension for // every extension defined in the pack. // If the build info is a JSON object, then the extension is standalone, and // we handle it as such. for (let buildInfo of buildInfos) { for (let [i, ext] of buildInfo.info.entries()) { const desc = descriptors.find(x => x.name === buildInfo.name); if (!desc) continue; extensions.push(new Extension(ext.type, desc.descriptor[i])); } } return extensions; } /** * Asynchronously reads every asset uploaded to the project. * * @since 1.0.0 * @access private * * @class * @param {Array} files An array of files present in the assets folderr of the AIA. * * @return {Promise<Array>} An array of AIAsset objects for the project being read. */ static async generateAssets(files) { const assets = []; for (let file of files) { // TODO: Lazily read the file content. const content = await getBlobFileContent(file); const [fileName, fileType] = getFileInfo(file); assets.push(new Asset(fileName, fileType, content)); } return assets; } } //# sourceMappingURL=aia_reader.js.map