UNPKG

pcf-scripts

Version:

This package contains a module for building PowerApps Component Framework (PCF) controls. See project homepage how to install.

155 lines (153 loc) 7.92 kB
"use strict"; // Copyright (C) Microsoft Corporation. All rights reserved. Object.defineProperty(exports, "__esModule", { value: true }); exports.ManifestProcessor = void 0; const lodash_1 = require("lodash"); const path = require("node:path"); const constants = require("./constants"); const controlManifest_1 = require("./controlManifest"); const diagnosticMessages_generated_1 = require("./diagnosticMessages.generated"); const featureManager_1 = require("./featureManager"); const PackageVersionUtils_1 = require("./generated/PackageVersionUtils"); class ManifestProcessor { constructor(manifestData, controlPath, diag) { this.resourcesMap = {}; this.nameTracker = {}; this.processedManifest = (0, lodash_1.cloneDeep)(manifestData); this.controlAbsPath = path.resolve(controlPath); this.controlRoot = path.dirname(this.controlAbsPath); this.diag = diag; this.nameTracker[constants.BUNDLE_NAME] = 1; this.featureManager = new featureManager_1.FeatureManager(); } // rename paths in <code> and <library>.<packaged_library> under <resources> // add built-by element as a child of control node; stamp PCF API version used getProcessedManifest() { this.addBuiltBy(); this.stampApiVersion(); this.addSubscribedFunctionalities(); this.processResources(); return { processedManifest: new controlManifest_1.ControlManifest(this.processedManifest), resourcesMap: this.resourcesMap, }; } addSubscribedFunctionalities() { const properties = this.processedManifest.manifest.control.property; if (properties) { if (properties.some((prop) => prop.$["of-type"] === "Object")) { this.addSubscribedFunctionality(constants.SF_SHARED_TEMPLATE, false); } } } addSubscribedFunctionality(functionality, isSubscribed) { let subFuncParentNode = this.processedManifest.manifest.control[constants.SUBSCRIBED_FUNCTIONALITY_SECTION_NODE]; subFuncParentNode ?? (subFuncParentNode = [ { "subscribed-functionality": [], }, ]); if (subFuncParentNode[0]["subscribed-functionality"].filter((el) => el.$.name === functionality).length === 0) { subFuncParentNode[0]["subscribed-functionality"].push({ $: { name: functionality, value: isSubscribed.toString(), }, }); } this.processedManifest.manifest.control[constants.SUBSCRIBED_FUNCTIONALITY_SECTION_NODE] = subFuncParentNode; } // rename paths specified by preview-image attribute as well as <code> and <library>.<packaged_library> under <resources> processResources() { const resources = this.processedManifest.manifest.control.resources; const previewImagePath = this.processedManifest.manifest.control.$["preview-image"]; if (previewImagePath) { this.processedManifest.manifest.control.$["preview-image"] = this.checkResourcePath(previewImagePath); } Object.entries(resources) .filter(([resourceType]) => resourceType !== constants.PLATFORM_LIBRARY_ELEM_NAME && resourceType !== constants.RES_DEPENDENCY_ELEM_NAME) .forEach(([resourceType, resourceList]) => { if (resourceType === constants.CODE_ELEM_NAME) { // the xsd allows more than one <code> element, but our opinionated build will validate // there is only one <code> element resourceList[0].$.path = constants.BUNDLE_NAME; } else if (resourceType === constants.LIBRARY_ELEM_NAME) { resourceList.forEach((lib) => { const packagedLibs = lib.packaged_library; if (packagedLibs) { packagedLibs.forEach((packagedLib) => { packagedLib.$.path = this.checkResourcePath(packagedLib.$.path, packagedLib.$.outputDirectory); }); } }); } else { resourceList.forEach((resource) => { resource.$.path = this.checkResourcePath(resource.$.path, resource.$.outputDirectory); }); } }); } // add built-by element as a child of control node addBuiltBy() { const buildToolVersion = (0, PackageVersionUtils_1.getPackageVersion)(constants.PCF_SCRIPTS_PACKAGE_NAME, this.controlRoot); if (!buildToolVersion) { this.diag.pushA(diagnosticMessages_generated_1.strings.package_version_not_found, [constants.PCF_SCRIPTS_PACKAGE_NAME]); return; } this.processedManifest.manifest.control["built-by"] = { $: { name: constants.BUILD_TOOL_NAME, version: buildToolVersion, }, }; } // obtain the version of the ComponentFramework API from the local package-lock.json and stamp it in CM.xml // optional parameter for unit test; return a boolean that indicates whether version info is found stampApiVersion() { const requireInternalTypings = this.featureManager.isFeatureEnabled("pcfUseInternalTypes"); const pcfPackage = requireInternalTypings ? constants.COMPONENT_FRAMEWORK_INTERNAL_PACKAGE_NAME : constants.COMPONENT_FRAMEWORK_PACKAGE_NAME; const apiVersion = (0, PackageVersionUtils_1.getPackageVersion)(pcfPackage, this.controlRoot); if (!apiVersion) { this.diag.pushA(diagnosticMessages_generated_1.strings.package_version_not_found, [constants.COMPONENT_FRAMEWORK_PACKAGE_NAME]); return; } this.processedManifest.manifest.control.$["api-version"] = apiVersion; } // First check whether the resource's relative path points to a file within the control folder. // If so, preserve the folder structure in outdir. If not, check whether a resource's file name collides // with any other resources file. If so returns a new file name otherwise return original name. checkResourcePath(resourceRelativePath, outputDirectory) { const resourceName = path.basename(resourceRelativePath); const resourceAbsPath = path.join(this.controlAbsPath, resourceRelativePath); const simplifiedRelativePath = path.relative(this.controlAbsPath, resourceAbsPath); let relativePathInOutDir; if (!simplifiedRelativePath.startsWith("..") && simplifiedRelativePath.length > 0) { relativePathInOutDir = simplifiedRelativePath; } else { relativePathInOutDir = resourceName; } // convert windows format to the path format in manifest relativePathInOutDir = outputDirectory ? path.join(outputDirectory, path.basename(relativePathInOutDir)).replace(/\\/g, "/") : relativePathInOutDir.replace(/\\/g, "/"); if (this.nameTracker[relativePathInOutDir]) { const ext = path.extname(relativePathInOutDir); const suffix = this.nameTracker[relativePathInOutDir]; // increment a number as suffix to differentiate files with existing names const newResourcePath = `${relativePathInOutDir.substring(0, relativePathInOutDir.length - ext.length)}${suffix}${ext}`; this.nameTracker[relativePathInOutDir]++; this.resourcesMap[resourceRelativePath] = newResourcePath; return newResourcePath; } else { this.nameTracker[relativePathInOutDir] = 1; this.resourcesMap[resourceRelativePath] = relativePathInOutDir; return relativePathInOutDir; } } } exports.ManifestProcessor = ManifestProcessor; //# sourceMappingURL=manifestProcessor.js.map