text: /**
   * Launch this script to re-generate the files containing the list of extensions
   * being used by each example.
   */
  const initializeGDevelopJs = require('../public/libGD.js');
  const { mapFor, mapVector } = require('./lib/MapFor');
  const makeExtensionsLoader = require('./lib/LocalJsExtensionsLoader');
  const { getExampleNames } = require('./lib/ExamplesLoader');
  const {
    readProjectFile,
    loadSerializedProject,
  } = require('./lib/LocalProjectOpener');
  const fs = require('fs');
  const _ = require('lodash');
  var shell = require('shelljs');
  
  shell.exec('node import-GDJS-Runtime.js');
  
  const outputFile = '../src/ProjectCreation/ExamplesInformation.js';
  
  const writeFile = object => {
    return new Promise((resolve, reject) => {
      const content = [
        `// This file is generated by update-examples-extensions-usage-from-resources-examples.js script`,
        `// prettier-ignore`,
        `module.exports = ${JSON.stringify(object, null, 2)};`,
        ``,
      ].join('\n');
      fs.writeFile(outputFile, content, err => {
        if (err) return reject(err);
  
        resolve();
      });
    });
  };
  
  const readFileContent = filename => {
    return new Promise((resolve, reject) => {
      fs.readFile(filename, 'utf8', (err, content) => {
        if (err) return reject(err);
  
        resolve(content);
      });
    });
  };
  
  initializeGDevelopJs().then(gd => {
    const getObjectTypes = projectOrLayout => {
      return _.uniq(
        mapFor(0, projectOrLayout.getObjectsCount(), i =>
          projectOrLayout.getObjectAt(i).getType()
        )
      );
    };
  
    const getBehaviorTypes = projectOrLayout => {
      return _.uniq(
        _.flatten(
          mapFor(0, projectOrLayout.getObjectsCount(), i => {
            const object = projectOrLayout.getObjectAt(i);
            const allBehaviorNames = object.getAllBehaviorNames();
            return mapVector(allBehaviorNames, behaviorName => {
              return object.getBehavior(behaviorName).getTypeName();
            });
          })
        )
      );
    };
  
    const getEventsAndInstructionsTypes = (project, events) => {
      const eventsTypesLister = new gd.EventsTypesLister(project);
      eventsTypesLister.launch(events);
      const types = {
        events: _.uniq(eventsTypesLister.getAllEventsTypes().toJSArray()),
        conditions: _.uniq(eventsTypesLister.getAllConditionsTypes().toJSArray()),
        actions: _.uniq(eventsTypesLister.getAllActionsTypes().toJSArray()),
      };
      eventsTypesLister.delete();
      return types;
    };
  
    const computeUsedExtensions = project => {
      // TODO: gd.WholeProjectRefactorer.exposeProjectEvents should be used to browse events
      // so that events functions are also browsed.
      const layoutExtensions = _.flatten(
        mapFor(0, project.getLayoutsCount(), i => {
          const layout = project.getLayoutAt(i);
          const extensionsFromObjects = getObjectTypes(layout).map(objectType => {
            return gd.MetadataProvider.getExtensionAndObjectMetadata(
              project.getCurrentPlatform(),
              objectType
            ).getExtension();
          });
          const extensionsFromBehaviors = getBehaviorTypes(layout).map(
            behaviorType => {
              return gd.MetadataProvider.getExtensionAndBehaviorMetadata(
                project.getCurrentPlatform(),
                behaviorType
              ).getExtension();
            }
          );
          const events = layout.getEvents();
          const eventsAndInstructionsTypes = getEventsAndInstructionsTypes(
            project,
            events
          );
          const extensionsFromConditions = eventsAndInstructionsTypes.conditions.map(
            conditionType => {
              return gd.MetadataProvider.getExtensionAndConditionMetadata(
                project.getCurrentPlatform(),
                conditionType
              ).getExtension();
            }
          );
          const extensionsFromActions = eventsAndInstructionsTypes.actions.map(
            actionType => {
              return gd.MetadataProvider.getExtensionAndActionMetadata(
                project.getCurrentPlatform(),
                actionType
              ).getExtension();
            }
          );
  
          return _.uniq([
            ...extensionsFromObjects,
            ...extensionsFromBehaviors,
            ...extensionsFromConditions,
            ...extensionsFromActions,
          ]);
        })
      );
      const externalEventsExtensions = _.flatten(
        mapFor(0, project.getExternalEventsCount(), i => {
          const externalEvents = project.getExternalEventsAt(i);
  
          const events = externalEvents.getEvents();
          const eventsAndInstructionsTypes = getEventsAndInstructionsTypes(
            project,
            events
          );
          const extensionsFromConditions = eventsAndInstructionsTypes.conditions.map(
            conditionType => {
              return gd.MetadataProvider.getExtensionAndConditionMetadata(
                project.getCurrentPlatform(),
                conditionType
              ).getExtension();
            }
          );
          const extensionsFromActions = eventsAndInstructionsTypes.actions.map(
            actionType => {
              return gd.MetadataProvider.getExtensionAndActionMetadata(
                project.getCurrentPlatform(),
                actionType
              ).getExtension();
            }
          );
  
          return _.uniq([...extensionsFromConditions, ...extensionsFromActions]);
        })
      );
  
      return _.uniq([...layoutExtensions, ...externalEventsExtensions]);
    };
  
    const noopTranslationFunction = str => str;
  
    const examplesInformation = {};
  
    makeExtensionsLoader({ gd, filterExamples: false })
      .loadAllExtensions(noopTranslationFunction)
      .then(loadingResults => {
        console.info('Loaded extensions', loadingResults);
  
        return getExampleNames();
      })
      .then(
        exampleNames => {
          return Promise.all(
            exampleNames.map(exampleName => {
              const exampleInformation = (examplesInformation[exampleName] = {
                description: '',
                usedExtensions: [],
              });
  
              return Promise.all([
                readProjectFile(
                  `../resources/examples/${exampleName}/${exampleName}.json`
                )
                  .then(projectObject => {
                    console.log(`Example "${exampleName}" loaded.`);
  
                    const project = loadSerializedProject(gd, projectObject);
                    const usedExtensions = computeUsedExtensions(project);
                    exampleInformation.usedExtensions = usedExtensions.map(
                      extension => ({
                        fullName: extension.getFullName(),
                        name: extension.getName(),
                      })
                    );
                  })
                  .catch(error => {
                    console.error('Error caught while analyzing game:', error);
                  }),
                readFileContent(
                  `../resources/examples/${exampleName}/README.md`
                ).then(
                  readmeContent => {
                    exampleInformation.description = readmeContent;
                  },
                  error => {
                    console.error(
                      `⚠️ No/invalid README found for ${exampleName}:`,
                      error
                    );
                  }
                ),
              ]);
            })
          );
        },
        err => console.error('Error while loading extensions', err)
      )
      .then(() => {
        return writeFile(examplesInformation);
      })
      .then(
        () => console.info('Done.'),
        err => console.error('Error while writing output', err)
      );
  });
  