import: async function()

in extensions/packageManager/src/node/index.ts [285:434]


    import: async function (req, res) {
      const user = await composer.context.getUserFromRequest(req);
      const projectId = req.params.projectId;
      const currentProject = await composer.getProjectById(projectId, user);
      const runtime = composer.getRuntimeByProject(currentProject);

      // get URL or package name
      const packageName = req.body.package;
      const version = req.body.version;
      const source = req.body.source;
      const isUpdating = req.body.isUpdating || false;
      const isPreview = req.body.isPreview || false;
      const mergeErrors: string[] = [];

      const captureErrors = (msg: string): void => {
        composer.log(msg);
        mergeErrors.push(msg);
      };

      const runtimePath = currentProject.getRuntimePath();

      if (packageName && runtimePath) {
        try {
          // Call the runtime's component install mechanism.
          const installOutput = await runtime.installComponent(
            runtimePath,
            packageName,
            version,
            source,
            currentProject,
            isPreview
          );

          const manifestFile = runtime.identifyManifest(runtimePath, currentProject.name);

          // call do a dry run on the dialog merge
          const dryrun = new SchemaMerger(
            [manifestFile, `!${path.join(currentProject.dir, 'generated')}/**`],
            path.join(currentProject.dataDir, 'schemas/sdk'),
            path.join(currentProject.dataDir, 'dialogs/imported'),
            true, // copy only? true = dry run
            false, // verbosity: true = verbose
            composer.log,
            composer.log,
            captureErrors
          );

          const dryRunMergeResults = await dryrun.merge();

          // evaluate dry run.
          // Did we have any conflicts that prevent moving forward? if so, install
          // Otherwise, copy the files into the project
          if (!dryRunMergeResults) {
            throw new Error('A problem occured during the install of this Component:\n' + mergeErrors.join('\n'));
          }

          // check the results to see if we have any problems
          if (dryRunMergeResults?.conflicts?.length && !isUpdating) {
            // we need to prompt the user to confirm the changes before proceeding
            res.json({
              success: false,
              components: dryRunMergeResults.components.filter(isAdaptiveComponent),
            });
          } else {
            const realMerge = new SchemaMerger(
              [manifestFile, `!${path.join(currentProject.dir, 'generated')}/**`],
              path.join(currentProject.dataDir, 'schemas/sdk'),
              path.join(currentProject.dataDir, 'dialogs/imported'),
              false, // copy only? true = dry run
              false, // verbosity: true = verbose
              composer.log,
              composer.log,
              composer.log
            );

            const mergeResults = await realMerge.merge();

            composer.log(
              'MERGE RESULTS',
              path.join(currentProject.dataDir, 'dialogs/imported'),
              JSON.stringify(mergeResults, null, 2)
            );

            const installedComponents = await loadPackageAssets(mergeResults.components.filter(isAdaptiveComponent));
            if (mergeResults) {
              let runtimeLanguage = 'c#';
              if (
                currentProject.settings.runtime.key === 'node-azurewebapp' ||
                currentProject.settings.runtime.key.startsWith('adaptive-runtime-js')
              ) {
                runtimeLanguage = 'js';
              }

              // update the settings.components array
              const newlyInstalledPlugin = installedComponents.find((c) => hasSchema(c) && c.name == packageName);
              if (
                newlyInstalledPlugin &&
                !currentProject.settings.runtimeSettings?.components?.find((p) => p.name === newlyInstalledPlugin.name)
              ) {
                const newSettings = await currentProject.getEnvSettings();
                // guard against missing settings keys
                if (!newSettings.runtimeSettings) {
                  newSettings.runtimeSettings = {
                    components: [],
                  };
                }
                if (!newSettings.runtimeSettings.components) {
                  newSettings.runtimeSettings.components = [];
                }
                newSettings.runtimeSettings.components.push({
                  name: newlyInstalledPlugin.name,
                  settingsPrefix: newlyInstalledPlugin.name,
                });
                currentProject.updateEnvSettings(newSettings);
              }
              updateRecentlyUsed(installedComponents, runtimeLanguage);

              res.json({
                success: true,
                components: installedComponents,
              });
            } else {
              res.json({
                success: false,
                results: 'Could not merge components',
              });
            }
          }
        } catch (err) {
          composer.log('Error in import', { message: err.message });
          try {
            await runtime.uninstallComponent(runtimePath, packageName, currentProject);
          } catch (err) {
            composer.log('Error uninstalling', err);
          }
          // if packageName is in the github form <username/package> remove the first part, because otherwise the unisntall doesn't work
          if (packageName.match(/.*\/.*/)) {
            const [user, realPackageName] = packageName.split(/\//);
            if (!user.match(/^@/)) {
              await runtime.uninstallComponent(runtimePath, realPackageName, currentProject);
            }
          }
          res.status(500).json({ success: false, message: err.message });
        }
      } else if (!runtimePath) {
        res.status(500).json({ message: 'Please eject your runtime before installing a package.' });
      } else {
        res.status(500).json({ message: 'Please specify a package name or git url to import.' });
      }
    },