lib/qx/tool/cli/commands/contrib/List.js
async function() {
      this.__repositories = [];
      this.__libraries = {};
      this.__latestCompatible = {};
      const localPathRepoName = this.self(arguments).localPathRepoName;

      let repos_cache = this.getCache().repos;

      // implicit qx contrib update
      if (repos_cache.list.length === 0 || this.getCache().version !== qx.tool.cli.ConfigSchemas.lockfile.version) {
        //await (new qx.tool.cli.commands.contrib.Update({quiet:true})).process();
      }

      let qooxdoo_version = await this.getUserQxVersion();
      let num_compat_repos = await this.__createIndexes(qooxdoo_version);
      if (this.argv.verbose) {
        console.log(`>>> We have ${num_compat_repos} contrib repositories which contain libraries compatible with qooxdoo version ${qooxdoo_version}`);
      }

      if (num_compat_repos === 0 && !this.argv.all && !this.argv.quiet) {
        console.info(
          `Currently, no contrib libraries with releases compatible with qooxdoo version ${qooxdoo_version} exist.`
        );
        return;
      }

      // detailed repo information
      let repo = this.argv.repository;
      if (repo) {
        if (!repos_cache.list.includes(repo)) {
          throw new qx.tool.cli.Utils.UserError(
            `Repository ${repo} does not exist or is not a qooxdoo contrib repo.`
          );
        }
        if (this.__libraries[repo] && this.__libraries[repo].length) {
          let columnify_options = {
            columnSplitter: "   ",
            config: {
              description: {maxWidth: 60},
              compatibility : {
                dataTransform: function(data) {
                  switch (data) {
                    case "false": return "not compatible / untested";
                    case "true": return "√";
                    default: return "";
                  }
                }
              }
            }
          };
          if (!this.argv.quiet) {
            console.info(columnify(this.__libraries[repo], columnify_options));
          }
        } else if (this.argv.verbose) {
          console.info(`Repository ${repo} does not contain suitable contrib libraries.`);
        }
        return;
      }

      // list output
      let columns = this.argv.short ?
        ["uri", "installedVersion", "latestVersion", "latestCompatible"] :
        ["uri", "name", "description", "installedVersion", "latestVersion", "latestCompatible"];
      if (this.argv.namespace || this.argv.installed) {
        columns.splice(1, 0, "namespace");
      }
      let columnify_options = {
        showHeaders: !this.argv.noheaders,
        columnSplitter: "   ",
        columns,
        config: {
          name: {maxWidth:25},
          description: {maxWidth: 60},
          installedVersion: {
            headingTransform : () => "INSTALLED",
            dataTransform: data => (data === "false" ? "" : data)
          },
          latestVersion: {
            headingTransform : () => "LATEST",
            dataTransform: data => (data === "false" ? "-" : data)
          },
          latestCompatible : {
            headingTransform : () => "COMPATIBLE",
            dataTransform: data => (data === "false" ? "-" : data)
          }
        }
      };
      // filter by compatibility unless --all
      let list =
        this.argv.all ?
          this.__repositories :
          this.__repositories.filter(item => item.latestCompatible || (this.argv.installed && item.name === localPathRepoName));
      // sort
      list.sort((l, r) => {
        l = l.name.toLowerCase();
        r = r.name.toLowerCase();
        return l < r ? -1 : l > r ? 1 : 0;
      });
      // list all libraries contained in a repo
      let expanded_list = [];
      for (let repo of list) {
        let repo_libs = [];
        if (!qx.lang.Type.isArray(this.__libraries[repo.name])) {
          continue;
        }
        for (let library of this.__libraries[repo.name]) {
          if (!semver.valid(library.version)) {
            console.warn(`>>> Ignoring '${repo.name}' ${library.name}': invalid version format '${library.version}'.`);
            continue;
          }
          if (repo.name === localPathRepoName || semver.eq(library.version, repo.latestVersion)) {
            let uri = repo.name === this.self(arguments).localPathRepoName ?
              library.path :
              path.join(repo.name, library.path || "");
            repo_libs.push({
              type: "library",
              uri,
              namespace: library.namespace,
              name: library.name,
              description: library.summary || repo.description,
              installedVersion: library.installedVersion,
              latestVersion: repo.latestVersion,
              latestCompatible: repo.latestCompatible
            });
          }
        }

        // add title to multiple-library repos
        if (repo_libs.length > 1 && !(this.argv["only-libraries"] || this.argv.short || repo.name === localPathRepoName)) {
          expanded_list.push({
            type: "repository",
            uri: repo.name,
            name: "",
            description: repo.description,
            installedVersion: "",
            latestVersion: repo.latestVersion,
            latestCompatible: repo.latestCompatible
          });
          if (!this.argv.json && !this.argv.installed && !this.argv.match) {
            // add an indent to group libraries in a repository
            repo_libs = repo_libs.map(lib => {
              lib.uri = "| " + lib.uri;
              return lib;
            });
          }
        }
        expanded_list = expanded_list.concat(repo_libs);
      }
      // filter by regular expression if requested
      if (this.argv.match) {
        let exp = new RegExp(this.argv.match, "i");
        expanded_list = expanded_list.filter(lib => lib.uri.match(exp) || lib.name.match(exp) || lib.description.match(exp));
      }

      // show only installed libraries if requested
      if (this.argv.installed) {
        expanded_list = expanded_list.filter(lib => Boolean(lib.installedVersion));
      }

      // output list
      if (this.argv.json) {
        // as JSON
        console.info(JSON.stringify(expanded_list, null, 2));
      } else if (!this.argv.quiet) {
        // as columns
        console.info(columnify(expanded_list, columnify_options));
        if (!this.argv.noheaders) {
          console.info();
          console.info("Note on columns: LATEST: Latest release that can be installed with this CLI;");
          console.info("                 COMPATIBLE: Latest release that is semver-compatible with the qooxdoo version used.");
          if (!this.argv.all) {
            console.info("To see all libraries, including potentially incompatible ones, use 'qx contrib list --all'.");
          }
        }
      }

      // save to cache
      this.getCache().compat[qooxdoo_version] = this.__latestCompatible[qooxdoo_version];
      await this.saveCache();
    }
async function() {
      this.__repositories = [];
      this.__libraries = {};
      this.__latestCompatible = {};
      const localPathRepoName = this.self(arguments).localPathRepoName;

      let repos_cache = this.getCache().repos;

      // implicit qx contrib update
      if (repos_cache.list.length === 0 || this.getCache().version !== qx.tool.cli.ConfigSchemas.lockfile.version) {
        //await (new qx.tool.cli.commands.contrib.Update({quiet:true})).process();
      }

      let qooxdoo_version = await this.getUserQxVersion();
      let num_compat_repos = await this.__createIndexes(qooxdoo_version);
      if (this.argv.verbose) {
        console.log(`>>> We have ${num_compat_repos} contrib repositories which contain libraries compatible with qooxdoo version ${qooxdoo_version}`);
      }

      if (num_compat_repos === 0 && !this.argv.all && !this.argv.quiet) {
        console.info(
          `Currently, no contrib libraries with releases compatible with qooxdoo version ${qooxdoo_version} exist.`
        );
        return;
      }

      // detailed repo information
      let repo = this.argv.repository;
      if (repo) {
        if (!repos_cache.list.includes(repo)) {
          throw new qx.tool.cli.Utils.UserError(
            `Repository ${repo} does not exist or is not a qooxdoo contrib repo.`
          );
        }
        if (this.__libraries[repo] && this.__libraries[repo].length) {
          let columnify_options = {
            columnSplitter: "   ",
            config: {
              description: {maxWidth: 60},
              compatibility : {
                dataTransform: function(data) {
                  switch (data) {
                    case "false": return "not compatible / untested";
                    case "true": return "√";
                    default: return "";
                  }
                }
              }
            }
          };
          if (!this.argv.quiet) {
            console.info(columnify(this.__libraries[repo], columnify_options));
          }
        } else if (this.argv.verbose) {
          console.info(`Repository ${repo} does not contain suitable contrib libraries.`);
        }
        return;
      }

      // list output
      let columns = this.argv.short ?
        ["uri", "installedVersion", "latestVersion", "latestCompatible"] :
        ["uri", "name", "description", "installedVersion", "latestVersion", "latestCompatible"];
      if (this.argv.namespace || this.argv.installed) {
        columns.splice(1, 0, "namespace");
      }
      let columnify_options = {
        showHeaders: !this.argv.noheaders,
        columnSplitter: "   ",
        columns,
        config: {
          name: {maxWidth:25},
          description: {maxWidth: 60},
          installedVersion: {
            headingTransform : () => "INSTALLED",
            dataTransform: data => (data === "false" ? "" : data)
          },
          latestVersion: {
            headingTransform : () => "LATEST",
            dataTransform: data => (data === "false" ? "-" : data)
          },
          latestCompatible : {
            headingTransform : () => "COMPATIBLE",
            dataTransform: data => (data === "false" ? "-" : data)
          }
        }
      };
      // filter by compatibility unless --all
      let list =
        this.argv.all ?
          this.__repositories :
          this.__repositories.filter(item => item.latestCompatible || (this.argv.installed && item.name === localPathRepoName));
      // sort
      list.sort((l, r) => {
        l = l.name.toLowerCase();
        r = r.name.toLowerCase();
        return l < r ? -1 : l > r ? 1 : 0;
      });
      // list all libraries contained in a repo
      let expanded_list = [];
      for (let repo of list) {
        let repo_libs = [];
        if (!qx.lang.Type.isArray(this.__libraries[repo.name])) {
          continue;
        }
        for (let library of this.__libraries[repo.name]) {
          if (!semver.valid(library.version)) {
            console.warn(`>>> Ignoring '${repo.name}' ${library.name}': invalid version format '${library.version}'.`);
            continue;
          }
          if (repo.name === localPathRepoName || semver.eq(library.version, repo.latestVersion)) {
            let uri = repo.name === this.self(arguments).localPathRepoName ?
              library.path :
              path.join(repo.name, library.path || "");
            repo_libs.push({
              type: "library",
              uri,
              namespace: library.namespace,
              name: library.name,
              description: library.summary || repo.description,
              installedVersion: library.installedVersion,
              latestVersion: repo.latestVersion,
              latestCompatible: repo.latestCompatible
            });
          }
        }

        // add title to multiple-library repos
        if (repo_libs.length > 1 && !(this.argv["only-libraries"] || this.argv.short || repo.name === localPathRepoName)) {
          expanded_list.push({
            type: "repository",
            uri: repo.name,
            name: "",
            description: repo.description,
            installedVersion: "",
            latestVersion: repo.latestVersion,
            latestCompatible: repo.latestCompatible
          });
          if (!this.argv.json && !this.argv.installed && !this.argv.match) {
            // add an indent to group libraries in a repository
            repo_libs = repo_libs.map(lib => {
              lib.uri = "| " + lib.uri;
              return lib;
            });
          }
        }
        expanded_list = expanded_list.concat(repo_libs);
      }
      // filter by regular expression if requested
      if (this.argv.match) {
        let exp = new RegExp(this.argv.match, "i");
        expanded_list = expanded_list.filter(lib => lib.uri.match(exp) || lib.name.match(exp) || lib.description.match(exp));
      }

      // show only installed libraries if requested
      if (this.argv.installed) {
        expanded_list = expanded_list.filter(lib => Boolean(lib.installedVersion));
      }

      // output list
      if (this.argv.json) {
        // as JSON
        console.info(JSON.stringify(expanded_list, null, 2));
      } else if (!this.argv.quiet) {
        // as columns
        console.info(columnify(expanded_list, columnify_options));
        if (!this.argv.noheaders) {
          console.info();
          console.info("Note on columns: LATEST: Latest release that can be installed with this CLI;");
          console.info("                 COMPATIBLE: Latest release that is semver-compatible with the qooxdoo version used.");
          if (!this.argv.all) {
            console.info("To see all libraries, including potentially incompatible ones, use 'qx contrib list --all'.");
          }
        }
      }

      // save to cache
      this.getCache().compat[qooxdoo_version] = this.__latestCompatible[qooxdoo_version];
      await this.saveCache();
    }
Lists contrib libraries compatible with the current project