lib/qx/tool/cli/commands/Migrate.js
async function() {
      var t = this;
      var compileAst = null;
      var compileJson = {};
      var configJson;

      var lets = {};
      function getMacro(name) {
        var value = lets[name];
        value = replaceMacros(value);
        return value;
      }

      function replaceMacros(value) {
        if (!value) {
          return "";
        }
        // eslint-disable-next-line no-constant-condition
        while (true) {
          var pos = value.indexOf("${");
          var endPos = value.indexOf("}", pos);
          if (pos < 0 || endPos < 0) {
            return value;
          }
          var name = value.substring(pos + 2, endPos);
          var left = value.substring(0, pos);
          var right = value.substring(endPos + 1);
          value = left + lets[name] + right;
        }
      }

      function parseJson(str) {
        var ast = JsonToAst.parseToAst(str);
        var json = JsonToAst.astToObject(ast);
        return json;
      }

      t.debug(">>> Loading config.json");
      var data;
      try {
        data = await readFile("config.json", {encoding: "utf8"});
      } catch (ex) {
        if (ex.code == "ENOENT") {
          return;
        }
        throw new qx.tool.cli.Utils.UserError("Cannot read config.json: " + (ex.message||ex.stack));
      }
      try {
        configJson = parseJson(data);
      } catch (ex) {
        throw new qx.tool.cli.Utils.UserError("Cannot parse config.json: " + (ex.message||ex.stack));
      }

      t.debug(">>> Loading compile.json (if there is one)");
      try {
        data = await readFile("compile.json", {encoding: "utf8"});
        try {
          compileAst = JsonToAst.parseToAst(data, {verbose: true});
          compileJson = JsonToAst.astToObject(compileAst);
        } catch (ex) {
          throw new qx.tool.cli.Utils.UserError("Cannot parse compile.json: " + (ex.message||ex.stack));
        }
      } catch (err) {
        if (err.code !== "ENOENT") {
          throw err;
        }
      }

      t.debug(">>> Loading Manifest.json");
      try {
        var str = await readFile("Manifest.json", {encoding: "utf8"});
        data = parseJson(str);
      } catch (ex) {
        data = null;
      }

      lets = (configJson && configJson["let"])||{};
      compileJson = Object.assign({
        applications: [],
        libraries: [],
        targets: [
          {
            "type": "source",
            "outputPath": "compiled/source"
          },
          {
            "type": "build",
            "outputPath": "compiled/build"
          }
        ],
        defaultTarget: "source",
        locales: getMacro("LOCALES")|| ["en"]
      }, compileJson);

      if (compileJson.libraries) {
        compileJson.libraries = compileJson.libraries.map(function(path) {
          if (typeof path === "object" && typeof path.path === "string") {
            return path.path;
          } else if (typeof path !== "string") {
            throw new qx.tool.cli.Utils.UserError("Cannot interpret configuration for libraries");
          }
          return path;
        });
      }

      if (!compileJson.defaultTarget) {
        const MAP_JOB_TO_TARGET = {
          "source": "source",
          "source-hybrid": "hybrid",
          "build": "build"
        };
        compileJson.defaultTarget = MAP_JOB_TO_TARGET[configJson["default-job"]]||"source";
      }

      var appName = getMacro("APPLICATION");
      var appClass = getMacro("APPLICATION_CLASS");
      if (!appClass) {
        appClass = appName + ".Application";
      }
      var qxTheme = getMacro("QXTHEME");

      t.debug(">>> Loading known library manifests");
      var libLookup = {};

      function addLibrary(ns, dir) {
        libLookup[ns] = {
          path: dir
        };
        compileJson.libraries.push(dir);
      }

      await Promise.all(compileJson.libraries.map(function(path) {
        return readFile(path + "/Manifest.json", {encoding: "utf8"})
          .then(function(data) {
            data = parseJson(data);
            var ns = data.provides.namespace;
            t.debug("    > Loaded " + ns);
            libLookup[ns] = {
              manifest: data,
              path: path
            };
          });
      }));

      if (configJson && configJson.jobs && configJson.libraries && configJson.libraries.library) {
        t.debug(">>> Loading extra library manifests");
        var all = configJson.libraries.library.map(async clib => {
          var filename = getMacro(clib.manifest);
          var pos = filename.lastIndexOf("/");
          var dir = filename.substring(pos + 1);
          var str = await readFile(filename, {encoding: "utf8"});
          var manifest = parseJson(str);
          var ns = manifest.provides.namespace;
          t.debug("    > Loaded " + ns);
          var lib = libLookup[ns];
          if (!lib) {
            addLibrary(ns, dir);
          }
        });
        await Promise.all(all);
      }

      this.info(">>> Configuring");
      if (!libLookup["qx"]) {
        var dir = getMacro("QOOXDOO_PATH");
        if (!dir) {
          throw new qx.tool.cli.Utils.UserError("Cannot find Qooxdoo in " + dir);
        } else {
          let p = path.join(dir, "framework");
          p = p.replace(/\\/g, "/");
          addLibrary("qx", p);
        }
      }

      if (appName.length && !libLookup[appName]) {
        addLibrary(appName, ".");
      }

      if (!compileJson.applications.length) {
        compileJson.applications.push({
          "class": appClass,
          theme: qxTheme,
          name: appName
        });
      }

      str = JsonToAst.reprint(compileJson, compileAst);
      await writeFile("compile.json", str, {encoding: "utf8"});
      this.info(">>> Done.");
    }
async function() {
      var t = this;
      var compileAst = null;
      var compileJson = {};
      var configJson;

      var lets = {};
      function getMacro(name) {
        var value = lets[name];
        value = replaceMacros(value);
        return value;
      }

      function replaceMacros(value) {
        if (!value) {
          return "";
        }
        // eslint-disable-next-line no-constant-condition
        while (true) {
          var pos = value.indexOf("${");
          var endPos = value.indexOf("}", pos);
          if (pos < 0 || endPos < 0) {
            return value;
          }
          var name = value.substring(pos + 2, endPos);
          var left = value.substring(0, pos);
          var right = value.substring(endPos + 1);
          value = left + lets[name] + right;
        }
      }

      function parseJson(str) {
        var ast = JsonToAst.parseToAst(str);
        var json = JsonToAst.astToObject(ast);
        return json;
      }

      t.debug(">>> Loading config.json");
      var data;
      try {
        data = await readFile("config.json", {encoding: "utf8"});
      } catch (ex) {
        if (ex.code == "ENOENT") {
          return;
        }
        throw new qx.tool.cli.Utils.UserError("Cannot read config.json: " + (ex.message||ex.stack));
      }
      try {
        configJson = parseJson(data);
      } catch (ex) {
        throw new qx.tool.cli.Utils.UserError("Cannot parse config.json: " + (ex.message||ex.stack));
      }

      t.debug(">>> Loading compile.json (if there is one)");
      try {
        data = await readFile("compile.json", {encoding: "utf8"});
        try {
          compileAst = JsonToAst.parseToAst(data, {verbose: true});
          compileJson = JsonToAst.astToObject(compileAst);
        } catch (ex) {
          throw new qx.tool.cli.Utils.UserError("Cannot parse compile.json: " + (ex.message||ex.stack));
        }
      } catch (err) {
        if (err.code !== "ENOENT") {
          throw err;
        }
      }

      t.debug(">>> Loading Manifest.json");
      try {
        var str = await readFile("Manifest.json", {encoding: "utf8"});
        data = parseJson(str);
      } catch (ex) {
        data = null;
      }

      lets = (configJson && configJson["let"])||{};
      compileJson = Object.assign({
        applications: [],
        libraries: [],
        targets: [
          {
            "type": "source",
            "outputPath": "compiled/source"
          },
          {
            "type": "build",
            "outputPath": "compiled/build"
          }
        ],
        defaultTarget: "source",
        locales: getMacro("LOCALES")|| ["en"]
      }, compileJson);

      if (compileJson.libraries) {
        compileJson.libraries = compileJson.libraries.map(function(path) {
          if (typeof path === "object" && typeof path.path === "string") {
            return path.path;
          } else if (typeof path !== "string") {
            throw new qx.tool.cli.Utils.UserError("Cannot interpret configuration for libraries");
          }
          return path;
        });
      }

      if (!compileJson.defaultTarget) {
        const MAP_JOB_TO_TARGET = {
          "source": "source",
          "source-hybrid": "hybrid",
          "build": "build"
        };
        compileJson.defaultTarget = MAP_JOB_TO_TARGET[configJson["default-job"]]||"source";
      }

      var appName = getMacro("APPLICATION");
      var appClass = getMacro("APPLICATION_CLASS");
      if (!appClass) {
        appClass = appName + ".Application";
      }
      var qxTheme = getMacro("QXTHEME");

      t.debug(">>> Loading known library manifests");
      var libLookup = {};

      function addLibrary(ns, dir) {
        libLookup[ns] = {
          path: dir
        };
        compileJson.libraries.push(dir);
      }

      await Promise.all(compileJson.libraries.map(function(path) {
        return readFile(path + "/Manifest.json", {encoding: "utf8"})
          .then(function(data) {
            data = parseJson(data);
            var ns = data.provides.namespace;
            t.debug("    > Loaded " + ns);
            libLookup[ns] = {
              manifest: data,
              path: path
            };
          });
      }));

      if (configJson && configJson.jobs && configJson.libraries && configJson.libraries.library) {
        t.debug(">>> Loading extra library manifests");
        var all = configJson.libraries.library.map(async clib => {
          var filename = getMacro(clib.manifest);
          var pos = filename.lastIndexOf("/");
          var dir = filename.substring(pos + 1);
          var str = await readFile(filename, {encoding: "utf8"});
          var manifest = parseJson(str);
          var ns = manifest.provides.namespace;
          t.debug("    > Loaded " + ns);
          var lib = libLookup[ns];
          if (!lib) {
            addLibrary(ns, dir);
          }
        });
        await Promise.all(all);
      }

      this.info(">>> Configuring");
      if (!libLookup["qx"]) {
        var dir = getMacro("QOOXDOO_PATH");
        if (!dir) {
          throw new qx.tool.cli.Utils.UserError("Cannot find Qooxdoo in " + dir);
        } else {
          let p = path.join(dir, "framework");
          p = p.replace(/\\/g, "/");
          addLibrary("qx", p);
        }
      }

      if (appName.length && !libLookup[appName]) {
        addLibrary(appName, ".");
      }

      if (!compileJson.applications.length) {
        compileJson.applications.push({
          "class": appClass,
          theme: qxTheme,
          name: appName
        });
      }

      str = JsonToAst.reprint(compileJson, compileAst);
      await writeFile("compile.json", str, {encoding: "utf8"});
      this.info(">>> Done.");
    }
/*
@Override