import type { BuildResult } from "project-editor/store/features"; import { EezObject, getProperty, MessageType } from "project-editor/core/object"; import { Project, BuildConfiguration, getProject, findAction, findPage, findBitmap, findStyle, findFont, findVariable } from "project-editor/project/project"; import { Style, getStyleProperty } from "project-editor/features/style/style"; import { Page } from "project-editor/features/page/page"; import { Font } from "project-editor/features/font/font"; import { Bitmap } from "project-editor/features/bitmap/bitmap"; import { Action } from "project-editor/features/action/action"; import { Variable } from "project-editor/features/variable/variable"; import { Flow } from "project-editor/flow/flow"; import { Component, ComponentInput, isFlowProperty, Widget } from "project-editor/flow/component"; import { buildActions, buildActionNames } from "project-editor/build/actions"; import { buildFlowGlobalVariablesEnum, buildVariableNames, buildVariables } from "project-editor/build/variables"; import { buildGuiStylesData, buildGuiStylesEnum } from "project-editor/build/styles"; import { buildGuiFontsData, buildGuiFontsEnum } from "project-editor/build/fonts"; import { buildGuiBitmapsData } from "project-editor/build/bitmaps"; import { buildGuiColors } from "project-editor/build/themes"; import { buildFlowData, buildFlowDefs, buildFlowStructs, buildFlowStructValues, buildFlowEnums } from "project-editor/build/flows"; import { buildGuiBitmapsEnum } from "project-editor/build/bitmaps"; import { buildGuiThemesEnum, buildGuiColorsEnum } from "project-editor/build/themes"; import { buildWidget } from "project-editor/build/widgets"; import { FlowValue, getValueType } from "project-editor/build/values"; import { getClassInfo, getObjectPathAsString, propertyNotFoundMessage, Section } from "project-editor/store"; import { ValueType } from "project-editor/features/variable/value-type"; import { build as buildV1 } from "project-editor/build/v1"; import { build as buildV2 } from "project-editor/build/v2"; import { dumpData, getName, NamingConvention, TAB } from "project-editor/build/helper"; import { FIRST_DASHBOARD_ACTION_COMPONENT_TYPE, FIRST_DASHBOARD_WIDGET_COMPONENT_TYPE, FIRST_LVGL_WIDGET_COMPONENT_TYPE } from "project-editor/flow/components/component-types"; import { DummyDataBuffer, DataBuffer } from "project-editor/build/data-buffer"; import { LVGLBuild } from "project-editor/lvgl/build"; import { ProjectEditor } from "project-editor/project-editor-interface"; import type { AssetsMap } from "eez-studio-types"; import { isDashboardProject } from "project-editor/project/project-type-traits"; import type { LVGLStyle } from "project-editor/lvgl/style"; export { DummyDataBuffer, DataBuffer } from "project-editor/build/data-buffer"; export const PATH_SEPARATOR = "//"; export class Assets { projects: Project[]; globalVariables: Variable[]; actions: Action[]; pages: (Page | undefined)[]; styles: Style[]; lvglStyles: LVGLStyle[]; fonts: Font[]; bitmaps: Bitmap[]; colors: string[]; flows: (Flow | undefined)[]; flowStates = new Map< Flow, { index: number; componentIndexes: Map; componentInputIndexes: Map; commponentInputs: ComponentInput[]; flowWidgetDataIndexes: Map; flowWidgetDataIndexToComponentPropertyValue: Map< number, { componentIndex: number; propertyValueIndex: number; } >; flowWidgetFromDataIndex: Map; flowWidgetActionIndexes: Map; flowWidgetActionIndexToComponentOutput: Map< number, { componentIndex: number; componentOutputIndex: number; } >; flowWidgetFromActionIndex: Map; } >(); jsonValues: any[] = []; constants: FlowValue[] = []; constantsMap = new Map< undefined | boolean | number | string | object, number >(); map: AssetsMap = { flows: [], flowIndexes: {}, actionFlowIndexes: {}, jsonValues: [], constants: [], globalVariables: [], dashboardComponentTypeToNameMap: {}, types: [], typeIndexes: {}, displayWidth: this.displayWidth, displayHeight: this.displayHeight, bitmaps: [], lvglWidgetIndexes: {}, lvglWidgetGeneratedIdentifiers: {} }; dashboardComponentClassNameToComponentIdMap: { [name: string]: number; } = {}; nextDashboardActionComponentId = FIRST_DASHBOARD_ACTION_COMPONENT_TYPE; nextDashboardWidgetComponentId = FIRST_DASHBOARD_WIDGET_COMPONENT_TYPE; nextLVGLWidgetComponentId = FIRST_LVGL_WIDGET_COMPONENT_TYPE; dashboardComponentTypeToNameMap: { [componentType: number]: string; } = {}; isUsingCrypyoSha256: boolean = false; lvglBuild: LVGLBuild; get projectStore() { return this.rootProject._store; } collectProjects(project: Project) { if (this.projects.indexOf(project) === -1) { this.projects.push(project); for (const importDirective of project.settings.general.imports) { if (importDirective.project) { this.collectProjects(importDirective.project); } } } } getAssets( getCollection: (project: Project) => T[], assetIncludePredicate: (asset: T) => boolean ) { const assets = []; for (const project of this.projects) { const collection = getCollection(project); if (collection) { assets.push(...collection.filter(assetIncludePredicate)); } } return assets; } constructor( public rootProject: Project, buildConfiguration: BuildConfiguration | undefined, public option: "check" | "buildAssets" | "buildFiles" ) { if (rootProject.projectTypeTraits.isLVGL) { this.lvglBuild = new LVGLBuild(this); this.lvglBuild.firtsPassStart(); } this.projectStore.typesStore.reset(); this.getConstantIndex(undefined, "undefined"); // undefined has value index 0 this.getConstantIndex(null, "null"); // null has value index 1 this.projects = []; this.collectProjects(rootProject); const assetIncludePredicate = (asset: Variable | Action | Page) => !buildConfiguration || !asset.usedIn || asset.usedIn.indexOf(buildConfiguration.name) !== -1; // // pages // this.pages = []; this.getAssets( project => project.pages, page => assetIncludePredicate(page) && page.id != undefined ).forEach(page => (this.pages[page.id! - 1] = page)); this.getAssets( project => project.pages, page => assetIncludePredicate(page) && page.id == undefined ).forEach(page => this.pages.push(page)); for (let i = 0; i < this.pages.length; i++) { if (!this.pages[i]) { this.projectStore.outputSectionsStore.write( Section.OUTPUT, MessageType.WARNING, `Missing page with ID = ${i + 1}`, this.rootProject.pages ); } } // // flows // this.flows = [ ...this.pages, ...this.getAssets( project => project.actions.filter( action => (this.option == "buildAssets" && action.id == undefined) || action.implementationType == "flow" ), assetIncludePredicate ) ]; this.flows.forEach(flow => flow && this.getFlowState(flow)); // // global variables // const nonNativeVariables = this.getAssets( project => project.variables ? project.variables.globalVariables : [], globalVariable => assetIncludePredicate(globalVariable) && !( (this.option == "buildFiles" || globalVariable.id != undefined) && globalVariable.native ) ); const nativeVariables: Variable[] = []; this.getAssets( project => project.variables ? project.variables.globalVariables : [], globalVariable => assetIncludePredicate(globalVariable) && globalVariable.native && globalVariable.id != undefined ).forEach( globalVariable => (nativeVariables[globalVariable.id! - 1] = globalVariable) ); this.getAssets( project => project.variables ? project.variables.globalVariables : [], globalVariable => assetIncludePredicate(globalVariable) && this.option == "buildFiles" && globalVariable.native && globalVariable.id == undefined ).forEach(globalVariable => nativeVariables.push(globalVariable)); for (let i = 0; i < nativeVariables.length; i++) { if (!nativeVariables[i]) { this.projectStore.outputSectionsStore.write( Section.OUTPUT, MessageType.WARNING, `Missing global variable with ID = ${i + 1}`, this.rootProject.variables.globalVariables ); for (let j = 0; j < nativeVariables.length; j++) { if (nativeVariables[j]) { nativeVariables[i] = nativeVariables[j]; break; } } } } this.globalVariables = [ // first non-native ...nonNativeVariables, // than native ...nativeVariables ]; // // actions // const nonNativeActions = this.getAssets( project => project.actions, action => assetIncludePredicate(action) && ((this.option != "buildFiles" && action.id == undefined) || action.implementationType != "native") ); const nativeActions: Action[] = []; this.getAssets( project => project.actions, action => assetIncludePredicate(action) && action.implementationType == "native" && action.id != undefined ).forEach(action => (nativeActions[action.id! - 1] = action)); this.getAssets( project => project.actions, action => assetIncludePredicate(action) && this.option == "buildFiles" && action.implementationType == "native" && action.id == undefined ).forEach(action => nativeActions.push(action)); for (let i = 0; i < nativeActions.length; i++) { if (!nativeActions[i]) { this.projectStore.outputSectionsStore.write( Section.OUTPUT, MessageType.WARNING, `Missing action with ID = ${i + 1}`, this.rootProject.actions ); for (let j = 0; j < nativeActions.length; j++) { if (nativeActions[j]) { nativeActions[i] = nativeActions[j]; break; } } } } this.actions = [ // first non-native ...nonNativeActions, // than native ...nativeActions ]; // // styles // this.styles = []; this.lvglStyles = []; this.getAssets