<commit_before>"use strict";

const path = require("path");
const fs = require("fs");
const execa = require("execa");
const { rollup } = require("rollup");
const webpack = require("webpack");
const { nodeResolve } = require("@rollup/plugin-node-resolve");
const rollupPluginAlias = require("@rollup/plugin-alias");
const commonjs = require("@rollup/plugin-commonjs");
const nodeGlobals = require("rollup-plugin-node-globals");
const json = require("@rollup/plugin-json");
const replace = require("@rollup/plugin-replace");
const { terser } = require("rollup-plugin-terser");
const { babel } = require("@rollup/plugin-babel");
const nativeShims = require("./rollup-plugins/native-shims");
const executable = require("./rollup-plugins/executable");
const evaluate = require("./rollup-plugins/evaluate");
const externals = require("./rollup-plugins/externals");

const PROJECT_ROOT = path.join(__dirname, "../..");

const EXTERNALS = [
  "assert",
  "buffer",
  "constants",
  "crypto",
  "events",
  "fs",
  "module",
  "os",
  "path",
  "stream",
  "url",
  "util",
  "readline",
  "tty",
];

const entries = [
  // Force using the CJS file, instead of ESM; i.e. get the file
  // from `"main"` instead of `"module"` (rollup default) of package.json
  {
    find: "outdent",
    replacement: require.resolve("outdent"),
  },
  {
    find: "lines-and-columns",
    replacement: require.resolve("lines-and-columns"),
  },
  {
    find: "@angular/compiler/src",
    replacement: path.resolve(
      `${PROJECT_ROOT}/node_modules/@angular/compiler/esm2015/src`
    ),
  },
  // Avoid rollup `SOURCEMAP_ERROR` and `THIS_IS_UNDEFINED` error
  {
    find: "@glimmer/syntax",
    replacement: require.resolve("@glimmer/syntax"),
  },
  // https://github.com/rollup/plugins/issues/670
  {
    find: "is-core-module",
    replacement: require.resolve("is-core-module"),
  },
  {
    find: "yaml/util",
    replacement: require.resolve("yaml/util"),
  },
];

function webpackNativeShims(config, modules) {
  if (!config.resolve) {
    config.resolve = {};
  }
  const { resolve } = config;
  resolve.alias = resolve.alias || {};
  resolve.fallback = resolve.fallback || {};
  for (const module of modules) {
    if (module in resolve.alias || module in resolve.fallback) {
      throw new Error(`fallback/alias for "${module}" already exists.`);
    }
    const file = path.join(__dirname, `shims/${module}.mjs`);
    if (fs.existsSync(file)) {
      resolve.alias[module] = file;
    } else {
      resolve.fallback[module] = false;
    }
  }
  return config;
}

function getBabelConfig(bundle) {
  const config = {
    babelrc: false,
    plugins: bundle.babelPlugins || [],
    compact: bundle.type === "plugin" ? false : "auto",
  };
  if (bundle.type === "core") {
    config.plugins.push(
      require.resolve("./babel-plugins/transform-custom-require")
    );
  }
  const targets = { node: "10" };
  if (bundle.target === "universal") {
    targets.browsers = [
      ">0.5%",
      "not ie 11",
      "not safari 5.1",
      "not op_mini all",
    ];
  }
  config.presets = [
    [
      require.resolve("@babel/preset-env"),
      {
        targets,
        exclude: ["transform-async-to-generator"],
        modules: false,
      },
    ],
  ];
  config.plugins.push([
    require.resolve("@babel/plugin-proposal-object-rest-spread"),
    { loose: true, useBuiltIns: true },
  ]);
  return config;
}

function getRollupConfig(bundle) {
  const config = {
    input: bundle.input,

    onwarn(warning) {
      if (
        // We use `eval("require")` to enable dynamic requires in the
        // custom parser API
        warning.code === "EVAL" ||
        // ignore `MIXED_EXPORTS` warn
        warning.code === "MIXED_EXPORTS" ||
        (warning.code === "CIRCULAR_DEPENDENCY" &&
          warning.importer.startsWith("node_modules"))
      ) {
        return;
      }

      // web bundle can't have external requires
      if (
        warning.code === "UNRESOLVED_IMPORT" &&
        bundle.target === "universal"
      ) {
        throw new Error(
          `Unresolved dependency in universal bundle: ${warning.source}`
        );
      }

      console.warn(warning);
    },
  };

  const replaceStrings = {
    "process.env.PRETTIER_TARGET": JSON.stringify(bundle.target),
    "process.env.NODE_ENV": JSON.stringify("production"),
  };
  if (bundle.target === "universal") {
    // We can't reference `process` in UMD bundles and this is
    // an undocumented "feature"
    replaceStrings["process.env.PRETTIER_DEBUG"] = "global.PRETTIER_DEBUG";
    // `rollup-plugin-node-globals` replace `__dirname` with the real dirname
    // `parser-typescript.js` will contain a path of working directory
    // See #8268
    replaceStrings.__filename = JSON.stringify(
      "/prettier-security-filename-placeholder.js"
    );
    replaceStrings.__dirname = JSON.stringify(
      "/prettier-security-dirname-placeholder"
    );
  }
  Object.assign(replaceStrings, bundle.replace);

  const babelConfig = { babelHelpers: "bundled", ...getBabelConfig(bundle) };

  const alias = { ...bundle.alias };
  alias.entries = [...entries, ...(alias.entries || [])];

  config.plugins = [
    replace({
      values: replaceStrings,
      delimiters: ["", ""],
    }),
    executable(),
    evaluate(),
    json(),
    rollupPluginAlias(alias),
    bundle.target === "universal" &&
      nativeShims(path.resolve(__dirname, "shims")),
    nodeResolve({
      extensions: [".js", ".json"],
      preferBuiltins: bundle.target === "node",
    }),
    commonjs({
      ignoreGlobal: bundle.target === "node",
      ...bundle.commonjs,
      ignore:
        bundle.type === "plugin"
          ? undefined
          : (id) => /\.\/parser-.*?/.test(id),
      requireReturnsDefault: "preferred",
    }),
    externals(bundle.externals),
    bundle.target === "universal" && nodeGlobals(),
    babel(babelConfig),
    bundle.minify !== false &&
      bundle.target === "universal" &&
      terser({
        output: {
          ascii_only: true,
        },
      }),
  ].filter(Boolean);

  if (bundle.target === "node") {
    config.external = EXTERNALS;
  }

  return config;
}

function getRollupOutputOptions(bundle, buildOptions) {
  const options = {
    // Avoid warning form #8797
    exports: "auto",
    file: `dist/${bundle.output}`,
  };

  if (bundle.target === "node") {
    options.format = "cjs";
  } else if (bundle.target === "universal") {
    options.name =
      bundle.type === "plugin" ? `prettierPlugins.${bundle.name}` : bundle.name;

    if (!bundle.format && bundle.bundler !== "webpack") {
      return [
        {
          ...options,
          format: "umd",
        },
        !buildOptions.playground && {
          ...options,
          format: "esm",
          file: `dist/esm/${bundle.output.replace(".js", ".mjs")}`,
        },
      ].filter(Boolean);
    }
    options.format = bundle.format;
  }

  if (buildOptions.playground && bundle.bundler !== "webpack") {
    return { skipped: true };
  }
  return [options];
}

function getWebpackConfig(bundle) {
  if (bundle.type !== "plugin" || bundle.target !== "universal") {
    throw new Error("Must use rollup for this bundle");
  }

  const root = path.resolve(__dirname, "..", "..");
  const config = {
    mode: "production",
    performance: { hints: false },
    entry: path.resolve(root, bundle.input),
    module: {
      rules: [
        {
          test: /\.js$/,
          use: {
            loader: "babel-loader",
            options: getBabelConfig(bundle),
          },
        },
      ],
    },
    output: {
      path: path.resolve(root, "dist"),
      filename: bundle.output,
      library: {
        type: "umd",
        name: ["prettierPlugins", bundle.name],
      },
      // https://github.com/webpack/webpack/issues/6642
      globalObject: 'new Function("return this")()',
    },
    optimization: {},
    resolve: {
      // Webpack@5 can't resolve "postcss/lib/parser" and "postcss/lib/stringifier"" imported by `postcss-scss`
      // Ignore `exports` field to fix bundle script
      exportsFields: [],
    },
  };

  if (bundle.terserOptions) {
    const TerserPlugin = require("terser-webpack-plugin");
    config.optimization.minimizer = [new TerserPlugin(bundle.terserOptions)];
  }
  // config.optimization.minimize = false;

  return webpackNativeShims(config, ["os", "path", "util", "url", "fs"]);
}

function runWebpack(config) {
  return new Promise((resolve, reject) => {
    webpack(config, (error, stats) => {
      if (error) {
        reject(error);
        return;
      }

      if (stats.hasErrors()) {
        const { errors } = stats.toJson();
        const error = new Error(errors[0].message);
        error.errors = errors;
        reject(error);
        return;
      }

      if (stats.hasWarnings()) {
        const { warnings } = stats.toJson();
        console.warn(warnings);
      }

      resolve();
    });
  });
}

async function checkCache(cache, inputOptions, outputOption) {
  const useCache = await cache.checkBundle(
    outputOption.file,
    inputOptions,
    outputOption
  );

  if (useCache) {
    try {
      await execa("cp", [
        path.join(cache.cacheDir, outputOption.file.replace("dist", "files")),
        outputOption.file,
      ]);
      return true;
    } catch (err) {
      console.log(err);
      // Proceed to build
    }
  }

  return false;
}

module.exports = async function createBundle(bundle, cache, options) {
  const inputOptions = getRollupConfig(bundle);
  const outputOptions = getRollupOutputOptions(bundle, options);

  if (!Array.isArray(outputOptions) && outputOptions.skipped) {
    return { skipped: true };
  }

  const checkCacheResults = await Promise.all(
    outputOptions.map((outputOption) =>
      checkCache(cache, inputOptions, outputOption)
    )
  );
  if (checkCacheResults.every((r) => r === true)) {
    return { cached: true };
  }

  if (bundle.bundler === "webpack") {
    await runWebpack(getWebpackConfig(bundle));
  } else {
    const result = await rollup(inputOptions);
    await Promise.all(outputOptions.map((option) => result.write(option)));
  }

  return { bundled: true };
};
<commit_msg>Check cache only when purge-cache is off (#10031)<commit_after>"use strict";

const path = require("path");
const fs = require("fs");
const execa = require("execa");
const { rollup } = require("rollup");
const webpack = require("webpack");
const { nodeResolve } = require("@rollup/plugin-node-resolve");
const rollupPluginAlias = require("@rollup/plugin-alias");
const commonjs = require("@rollup/plugin-commonjs");
const nodeGlobals = require("rollup-plugin-node-globals");
const json = require("@rollup/plugin-json");
const replace = require("@rollup/plugin-replace");
const { terser } = require("rollup-plugin-terser");
const { babel } = require("@rollup/plugin-babel");
const nativeShims = require("./rollup-plugins/native-shims");
const executable = require("./rollup-plugins/executable");
const evaluate = require("./rollup-plugins/evaluate");
const externals = require("./rollup-plugins/externals");

const PROJECT_ROOT = path.join(__dirname, "../..");

const EXTERNALS = [
  "assert",
  "buffer",
  "constants",
  "crypto",
  "events",
  "fs",
  "module",
  "os",
  "path",
  "stream",
  "url",
  "util",
  "readline",
  "tty",
];

const entries = [
  // Force using the CJS file, instead of ESM; i.e. get the file
  // from `"main"` instead of `"module"` (rollup default) of package.json
  {
    find: "outdent",
    replacement: require.resolve("outdent"),
  },
  {
    find: "lines-and-columns",
    replacement: require.resolve("lines-and-columns"),
  },
  {
    find: "@angular/compiler/src",
    replacement: path.resolve(
      `${PROJECT_ROOT}/node_modules/@angular/compiler/esm2015/src`
    ),
  },
  // Avoid rollup `SOURCEMAP_ERROR` and `THIS_IS_UNDEFINED` error
  {
    find: "@glimmer/syntax",
    replacement: require.resolve("@glimmer/syntax"),
  },
  // https://github.com/rollup/plugins/issues/670
  {
    find: "is-core-module",
    replacement: require.resolve("is-core-module"),
  },
  {
    find: "yaml/util",
    replacement: require.resolve("yaml/util"),
  },
];

function webpackNativeShims(config, modules) {
  if (!config.resolve) {
    config.resolve = {};
  }
  const { resolve } = config;
  resolve.alias = resolve.alias || {};
  resolve.fallback = resolve.fallback || {};
  for (const module of modules) {
    if (module in resolve.alias || module in resolve.fallback) {
      throw new Error(`fallback/alias for "${module}" already exists.`);
    }
    const file = path.join(__dirname, `shims/${module}.mjs`);
    if (fs.existsSync(file)) {
      resolve.alias[module] = file;
    } else {
      resolve.fallback[module] = false;
    }
  }
  return config;
}

function getBabelConfig(bundle) {
  const config = {
    babelrc: false,
    plugins: bundle.babelPlugins || [],
    compact: bundle.type === "plugin" ? false : "auto",
  };
  if (bundle.type === "core") {
    config.plugins.push(
      require.resolve("./babel-plugins/transform-custom-require")
    );
  }
  const targets = { node: "10" };
  if (bundle.target === "universal") {
    targets.browsers = [
      ">0.5%",
      "not ie 11",
      "not safari 5.1",
      "not op_mini all",
    ];
  }
  config.presets = [
    [
      require.resolve("@babel/preset-env"),
      {
        targets,
        exclude: ["transform-async-to-generator"],
        modules: false,
      },
    ],
  ];
  config.plugins.push([
    require.resolve("@babel/plugin-proposal-object-rest-spread"),
    { loose: true, useBuiltIns: true },
  ]);
  return config;
}

function getRollupConfig(bundle) {
  const config = {
    input: bundle.input,

    onwarn(warning) {
      if (
        // We use `eval("require")` to enable dynamic requires in the
        // custom parser API
        warning.code === "EVAL" ||
        // ignore `MIXED_EXPORTS` warn
        warning.code === "MIXED_EXPORTS" ||
        (warning.code === "CIRCULAR_DEPENDENCY" &&
          warning.importer.startsWith("node_modules"))
      ) {
        return;
      }

      // web bundle can't have external requires
      if (
        warning.code === "UNRESOLVED_IMPORT" &&
        bundle.target === "universal"
      ) {
        throw new Error(
          `Unresolved dependency in universal bundle: ${warning.source}`
        );
      }

      console.warn(warning);
    },
  };

  const replaceStrings = {
    "process.env.PRETTIER_TARGET": JSON.stringify(bundle.target),
    "process.env.NODE_ENV": JSON.stringify("production"),
  };
  if (bundle.target === "universal") {
    // We can't reference `process` in UMD bundles and this is
    // an undocumented "feature"
    replaceStrings["process.env.PRETTIER_DEBUG"] = "global.PRETTIER_DEBUG";
    // `rollup-plugin-node-globals` replace `__dirname` with the real dirname
    // `parser-typescript.js` will contain a path of working directory
    // See #8268
    replaceStrings.__filename = JSON.stringify(
      "/prettier-security-filename-placeholder.js"
    );
    replaceStrings.__dirname = JSON.stringify(
      "/prettier-security-dirname-placeholder"
    );
  }
  Object.assign(replaceStrings, bundle.replace);

  const babelConfig = { babelHelpers: "bundled", ...getBabelConfig(bundle) };

  const alias = { ...bundle.alias };
  alias.entries = [...entries, ...(alias.entries || [])];

  config.plugins = [
    replace({
      values: replaceStrings,
      delimiters: ["", ""],
    }),
    executable(),
    evaluate(),
    json(),
    rollupPluginAlias(alias),
    bundle.target === "universal" &&
      nativeShims(path.resolve(__dirname, "shims")),
    nodeResolve({
      extensions: [".js", ".json"],
      preferBuiltins: bundle.target === "node",
    }),
    commonjs({
      ignoreGlobal: bundle.target === "node",
      ...bundle.commonjs,
      ignore:
        bundle.type === "plugin"
          ? undefined
          : (id) => /\.\/parser-.*?/.test(id),
      requireReturnsDefault: "preferred",
    }),
    externals(bundle.externals),
    bundle.target === "universal" && nodeGlobals(),
    babel(babelConfig),
    bundle.minify !== false &&
      bundle.target === "universal" &&
      terser({
        output: {
          ascii_only: true,
        },
      }),
  ].filter(Boolean);

  if (bundle.target === "node") {
    config.external = EXTERNALS;
  }

  return config;
}

function getRollupOutputOptions(bundle, buildOptions) {
  const options = {
    // Avoid warning form #8797
    exports: "auto",
    file: `dist/${bundle.output}`,
  };

  if (bundle.target === "node") {
    options.format = "cjs";
  } else if (bundle.target === "universal") {
    options.name =
      bundle.type === "plugin" ? `prettierPlugins.${bundle.name}` : bundle.name;

    if (!bundle.format && bundle.bundler !== "webpack") {
      return [
        {
          ...options,
          format: "umd",
        },
        !buildOptions.playground && {
          ...options,
          format: "esm",
          file: `dist/esm/${bundle.output.replace(".js", ".mjs")}`,
        },
      ].filter(Boolean);
    }
    options.format = bundle.format;
  }

  if (buildOptions.playground && bundle.bundler !== "webpack") {
    return { skipped: true };
  }
  return [options];
}

function getWebpackConfig(bundle) {
  if (bundle.type !== "plugin" || bundle.target !== "universal") {
    throw new Error("Must use rollup for this bundle");
  }

  const root = path.resolve(__dirname, "..", "..");
  const config = {
    mode: "production",
    performance: { hints: false },
    entry: path.resolve(root, bundle.input),
    module: {
      rules: [
        {
          test: /\.js$/,
          use: {
            loader: "babel-loader",
            options: getBabelConfig(bundle),
          },
        },
      ],
    },
    output: {
      path: path.resolve(root, "dist"),
      filename: bundle.output,
      library: {
        type: "umd",
        name: ["prettierPlugins", bundle.name],
      },
      // https://github.com/webpack/webpack/issues/6642
      globalObject: 'new Function("return this")()',
    },
    optimization: {},
    resolve: {
      // Webpack@5 can't resolve "postcss/lib/parser" and "postcss/lib/stringifier"" imported by `postcss-scss`
      // Ignore `exports` field to fix bundle script
      exportsFields: [],
    },
  };

  if (bundle.terserOptions) {
    const TerserPlugin = require("terser-webpack-plugin");
    config.optimization.minimizer = [new TerserPlugin(bundle.terserOptions)];
  }
  // config.optimization.minimize = false;

  return webpackNativeShims(config, ["os", "path", "util", "url", "fs"]);
}

function runWebpack(config) {
  return new Promise((resolve, reject) => {
    webpack(config, (error, stats) => {
      if (error) {
        reject(error);
        return;
      }

      if (stats.hasErrors()) {
        const { errors } = stats.toJson();
        const error = new Error(errors[0].message);
        error.errors = errors;
        reject(error);
        return;
      }

      if (stats.hasWarnings()) {
        const { warnings } = stats.toJson();
        console.warn(warnings);
      }

      resolve();
    });
  });
}

async function checkCache(cache, inputOptions, outputOption) {
  const useCache = await cache.checkBundle(
    outputOption.file,
    inputOptions,
    outputOption
  );

  if (useCache) {
    try {
      await execa("cp", [
        path.join(cache.cacheDir, outputOption.file.replace("dist", "files")),
        outputOption.file,
      ]);
      return true;
    } catch (err) {
      console.log(err);
      // Proceed to build
    }
  }

  return false;
}

module.exports = async function createBundle(bundle, cache, options) {
  const inputOptions = getRollupConfig(bundle);
  const outputOptions = getRollupOutputOptions(bundle, options);

  if (!Array.isArray(outputOptions) && outputOptions.skipped) {
    return { skipped: true };
  }

  if (
    !options["purge-cache"] &&
    (
      await Promise.all(
        outputOptions.map((outputOption) =>
          checkCache(cache, inputOptions, outputOption)
        )
      )
    ).every((cached) => cached)
  ) {
    return { cached: true };
  }

  if (bundle.bundler === "webpack") {
    await runWebpack(getWebpackConfig(bundle));
  } else {
    const result = await rollup(inputOptions);
    await Promise.all(outputOptions.map((option) => result.write(option)));
  }

  return { bundled: true };
};
<|endoftext|>


<commit_before>'use strict';

var numberFilter = require('./number');

var units = {
    ml: 1000,
    cl: 100,
    dl: 10,
    l: 1,
    liter: 1
};

module.exports = function volumeFilter(val) {
    if (typeof val === 'number') {
        return val;
    } else if (val === '') {
        return null;
    }

    var unit = val.match(/(ml|cl|dl|l|liter)/) || [];
    var amount = numberFilter.greedy(val);
    var factor = units[unit[1]] || 1;

    return amount / factor;
};
<commit_msg>Return null if 'val' is falsy<commit_after>'use strict';

var numberFilter = require('./number');

var units = {
    ml: 1000,
    cl: 100,
    dl: 10,
    l: 1,
    liter: 1
};

module.exports = function volumeFilter(val) {
    if (!val) {
        return null;
    } else if (typeof val === 'number') {
        return val;
    }

    var unit = val.match(/(ml|cl|dl|l|liter)/) || [];
    var amount = numberFilter.greedy(val);
    var factor = units[unit[1]] || 1;

    return amount / factor;
};
<|endoftext|>


<commit_before>/*global abaplint*/
/*global CodeMirror*/

const filename = "zfoobar.prog.abap";

let registry = new abaplint.Registry().addFile(new abaplint.File(filename, "dummy"));

function escape(str) {
  str = str.replace(/&/g, "&");
  str = str.replace(/>/g, ">");
  str = str.replace(/</g, "<");
  str = str.replace(/"/g, """);
  str = str.replace(/'/g, "'");
  return str;
}

function stripNewline(input) {
  let result = input;
  while (result.substr(result.length - 1, 1) === "\n") {
    result = result.substr(0, result.length - 1);
  }
  return result;
}

function linkToStatement(statement) {
  return "" +
    statement.constructor.name + "";
}

function linkToStructure(structure) {
  return "" +
    structure.constructor.name + "";
}

function linkToExpression(expression) {
  return "" +
    expression.constructor.name + "";
}

function outputNodes(nodes) {
  let ret = "
";
  for (let node of nodes) {
    let extra = "";
    switch(node.constructor.name) {
      case "TokenNode":
        extra = node.get().constructor.name + ", \"" + node.get().getStr() + "\"";
        break;
      case "ExpressionNode":
        extra = linkToExpression(node.get()) + outputNodes(node.getChildren());
        break;
    }

    ret = ret + "
" + node.constructor.name + ", " + extra + "
";
  }
  return ret + "
";
}

function buildStatements(file) {
  let output = "";

  for (let statement of file.getStatements()) {
    let row = statement.getStart().getRow();
    let col = statement.getStart().getCol();
    let erow = statement.getEnd().getRow();
    let ecol = statement.getEnd().getCol();
// getting the class name only works if uglify does not mangle names
    output = output +
      "
" +
      row + ": " +
      linkToStatement(statement.get()) +
      "
\n" + outputNodes(statement.getChildren());
  }

  return output;
}

function buildStructure(nodes) {
  let output = "
";
  for(let node of nodes) {
    if (node instanceof abaplint.Nodes.StructureNode) {
      output = output + "
" + linkToStructure(node.get()) + ", Structure " + buildStructure(node.getChildren()) + "
";
    } else if (node instanceof abaplint.Nodes.StatementNode) {
      output = output + "
" + linkToStatement(node.get()) + ", Statement
";
    }
  }
  return output + "
";
}

function process(val = undefined) {
  let input = stripNewline(val ? val : editor.getValue());
  let file = new abaplint.File(filename, input);
  return registry.updateFile(file).findIssues();
}

function parse() {
  let input = stripNewline(editor.getValue());
  let file = new abaplint.File(filename, input);
  return registry.updateFile(file).parse().getABAPFiles()[0];
}

// ---------------------

function issues() {
  let issues = process();
  let json = JSON.parse(abaplint.Formatter.format(issues, "json"));
  let output = "";
  for (let issue of json) {
    output = output +
      "
" +
      "[" + issue.start.row + ", "+ issue.start.col + "] " +
      escape(issue.description) +
      "
\n";
  }
  document.getElementById("info").innerHTML = output;
}

function tokens() {
  let file = parse();

  let inner = "

String	Type	Row	Column
";
  for (let token of file.getTokens()) {
    inner = inner + "
\"" +
      escape(token.getStr()) + "\"	" +
      token.constructor.name + "	" +
      token.getRow() + "	" +
      token.getCol() + "
";
  }
  inner = inner + "
";

  document.getElementById("info").innerHTML = inner;
}

function statements() {
  document.getElementById("info").innerHTML = buildStatements(parse());
}

function structure() {
  document.getElementById("info").innerHTML = buildStructure([parse().getStructure()]);
}

// ---------------------

var editor = null;
var _mark = null;

function markLine(line, col, eline, ecol) {
  if (_mark) _mark.clear();
  if (!col) col = 0;
  if (!eline) eline = line;
  if (!ecol) ecol = 100;
  _mark = editor.markText({line: line - 1, ch: col - 1},
                          {line: eline - 1, ch: ecol - 1},
                          {className: "styled-background"});
  editor.scrollIntoView({line: line - 1, ch: 0}, 200);
}

function changeVersion(evt) {
  let conf = registry.getConfig();
  conf.setVersion(abaplint.textToVersion(evt.target.value));
  registry.setConfig(conf);
}

function popuplateVersionDropdown() {
  let options = "";
  for(let version in abaplint.Version) {
    if (!isNaN(Number(version))) {
      let selected = "";
      if (abaplint.Config.defaultVersion + "" === version + "") { // huh?
        selected = " selected";
      }
      options = options + "<option value=\"" + abaplint.Version[version] + "\"" + selected + ">" +
        abaplint.Version[version] + "</option>\n";
    }
  }
  document.getElementById("version_dropdown").innerHTML = options;
  document.getElementById("version_dropdown").onchange = changeVersion;
}

function validator(text, options) {
  let ret = [];
  for (let issue of process(text)) {
    const hint = {
      message: issue.getMessage(),
      severity: "error",
      from: CodeMirror.Pos(issue.getStart().getRow() - 1, issue.getStart().getCol() - 1),
      to: CodeMirror.Pos(issue.getEnd().getRow() - 1, issue.getEnd().getCol() - 1)
    };
    ret.push(hint);
  }
  return ret;
}

function prettyPrint(cm) {
  const pretty = new abaplint.PrettyPrinter(registry.getABAPFiles()[0]);
  cm.doc.setValue(pretty.run());
}

function run() {
  CodeMirror.registerHelper("lint", "abap", validator);
  editor = CodeMirror.fromTextArea(document.getElementById("input"), {
    lineNumbers: true,
    lint: true,
    theme: "mbo",
    tabSize: 2,
    gutters: ["CodeMirror-lint-markers"],
    styleSelectedText: true,
    mode: "abap"
  });
  popuplateVersionDropdown();
  editor.setSize(null, "100%");
  editor.setOption("extraKeys", {
    "Shift-F1": prettyPrint
  });
  document.getElementById("abaplintver").innerHTML = abaplint.Registry.abaplintVersion();
}

run();<commit_msg>playground: output issue key<commit_after>/*global abaplint*/
/*global CodeMirror*/

const filename = "zfoobar.prog.abap";

let registry = new abaplint.Registry().addFile(new abaplint.File(filename, "dummy"));

function escape(str) {
  str = str.replace(/&/g, "&");
  str = str.replace(/>/g, ">");
  str = str.replace(/</g, "<");
  str = str.replace(/"/g, """);
  str = str.replace(/'/g, "'");
  return str;
}

function stripNewline(input) {
  let result = input;
  while (result.substr(result.length - 1, 1) === "\n") {
    result = result.substr(0, result.length - 1);
  }
  return result;
}

function linkToStatement(statement) {
  return "" +
    statement.constructor.name + "";
}

function linkToStructure(structure) {
  return "" +
    structure.constructor.name + "";
}

function linkToExpression(expression) {
  return "" +
    expression.constructor.name + "";
}

function outputNodes(nodes) {
  let ret = "
";
  for (let node of nodes) {
    let extra = "";
    switch(node.constructor.name) {
      case "TokenNode":
        extra = node.get().constructor.name + ", \"" + node.get().getStr() + "\"";
        break;
      case "ExpressionNode":
        extra = linkToExpression(node.get()) + outputNodes(node.getChildren());
        break;
    }

    ret = ret + "
" + node.constructor.name + ", " + extra + "
";
  }
  return ret + "
";
}

function buildStatements(file) {
  let output = "";

  for (let statement of file.getStatements()) {
    let row = statement.getStart().getRow();
    let col = statement.getStart().getCol();
    let erow = statement.getEnd().getRow();
    let ecol = statement.getEnd().getCol();
// getting the class name only works if uglify does not mangle names
    output = output +
      "
" +
      row + ": " +
      linkToStatement(statement.get()) +
      "
\n" + outputNodes(statement.getChildren());
  }

  return output;
}

function buildStructure(nodes) {
  let output = "
";
  for(let node of nodes) {
    if (node instanceof abaplint.Nodes.StructureNode) {
      output = output + "
" + linkToStructure(node.get()) + ", Structure " + buildStructure(node.getChildren()) + "
";
    } else if (node instanceof abaplint.Nodes.StatementNode) {
      output = output + "
" + linkToStatement(node.get()) + ", Statement
";
    }
  }
  return output + "
";
}

function process(val = undefined) {
  let input = stripNewline(val ? val : editor.getValue());
  let file = new abaplint.File(filename, input);
  return registry.updateFile(file).findIssues();
}

function parse() {
  let input = stripNewline(editor.getValue());
  let file = new abaplint.File(filename, input);
  return registry.updateFile(file).parse().getABAPFiles()[0];
}

// ---------------------

function issues() {
  let issues = process();
  let json = JSON.parse(abaplint.Formatter.format(issues, "json"));
  let output = "";
  for (let issue of json) {
    output = output +
      "
" +
      "[" + issue.start.row + ", "+ issue.start.col + "] " +
      escape(issue.description) + " (" +
      issue.key +
      ")
\n";
  }
  document.getElementById("info").innerHTML = output;
}

function tokens() {
  let file = parse();

  let inner = "

String	Type	Row	Column
";
  for (let token of file.getTokens()) {
    inner = inner + "
\"" +
      escape(token.getStr()) + "\"	" +
      token.constructor.name + "	" +
      token.getRow() + "	" +
      token.getCol() + "
";
  }
  inner = inner + "
";

  document.getElementById("info").innerHTML = inner;
}

function statements() {
  document.getElementById("info").innerHTML = buildStatements(parse());
}

function structure() {
  document.getElementById("info").innerHTML = buildStructure([parse().getStructure()]);
}

// ---------------------

var editor = null;
var _mark = null;

function markLine(line, col, eline, ecol) {
  if (_mark) _mark.clear();
  if (!col) col = 0;
  if (!eline) eline = line;
  if (!ecol) ecol = 100;
  _mark = editor.markText({line: line - 1, ch: col - 1},
                          {line: eline - 1, ch: ecol - 1},
                          {className: "styled-background"});
  editor.scrollIntoView({line: line - 1, ch: 0}, 200);
}

function changeVersion(evt) {
  let conf = registry.getConfig();
  conf.setVersion(abaplint.textToVersion(evt.target.value));
  registry.setConfig(conf);
}

function popuplateVersionDropdown() {
  let options = "";
  for(let version in abaplint.Version) {
    if (!isNaN(Number(version))) {
      let selected = "";
      if (abaplint.Config.defaultVersion + "" === version + "") { // huh?
        selected = " selected";
      }
      options = options + "<option value=\"" + abaplint.Version[version] + "\"" + selected + ">" +
        abaplint.Version[version] + "</option>\n";
    }
  }
  document.getElementById("version_dropdown").innerHTML = options;
  document.getElementById("version_dropdown").onchange = changeVersion;
}

function validator(text, options) {
  let ret = [];
  for (let issue of process(text)) {
    const hint = {
      message: issue.getMessage(),
      severity: "error",
      from: CodeMirror.Pos(issue.getStart().getRow() - 1, issue.getStart().getCol() - 1),
      to: CodeMirror.Pos(issue.getEnd().getRow() - 1, issue.getEnd().getCol() - 1)
    };
    ret.push(hint);
  }
  return ret;
}

function prettyPrint(cm) {
  const pretty = new abaplint.PrettyPrinter(registry.getABAPFiles()[0]);
  cm.doc.setValue(pretty.run());
}

function run() {
  CodeMirror.registerHelper("lint", "abap", validator);
  editor = CodeMirror.fromTextArea(document.getElementById("input"), {
    lineNumbers: true,
    lint: true,
    theme: "mbo",
    tabSize: 2,
    gutters: ["CodeMirror-lint-markers"],
    styleSelectedText: true,
    mode: "abap"
  });
  popuplateVersionDropdown();
  editor.setSize(null, "100%");
  editor.setOption("extraKeys", {
    "Shift-F1": prettyPrint
  });
  document.getElementById("abaplintver").innerHTML = abaplint.Registry.abaplintVersion();
}

run();<|endoftext|>


<commit_before>/* NODE MODULES */

/** LOCAL OBJECT
 * @property {} -
 */
var EXCEPTIONS = {
    'default': ['Default', 'Unhandled exception.'],
    'no options': ['No options', 'Parameter "options" in jsfly.wingify(options) must be an object.'],
    'wrong type': ['Wrong type', 'The "options.type" provided to jsfly.wingify(options) is invalid.'],
    'no code': ['No code', 'jsfly.wingify() was called without supplying a function.'],
    'no function': ['No function', 'Parameter "code" in jsfly.wingify(code) must be a function.'],
    'nostring function': ['No string code', 'The name/tag/options.name parameters supplied to jsfly.wingify(function) must be a string.'],
    'unnamed function': ['Unnamed code', 'The function supplied to jsfly.wingify(function) must be a named function or have a tag attribute.']

    //'new function': ['New Function', 'jsfly.wingify() must be an object.']
};

/** MODULE INTERFACE
 *@method {function} -
 */
module.exports.throwNew = function returnExceptionObject(exceptionName) {
    var exception = EXCEPTIONS[exceptionName] || EXCEPTIONS['default'];

    return {
        name:  exception[0],
        message: exception[1]
    }
};
<commit_msg>Added exceptions to airport#create parameter validation.<commit_after>/* NODE MODULES */

/** LOCAL OBJECT
 * @property {} -
 */
var EXCEPTIONS = {
    'default': ['Default', 'Unhandled exception.'],
    'no options': ['No options', 'Parameter "options" in jsfly.wingify(options) must be an object.'],
    'wrong type': ['Wrong type', 'The "options.type" provided to jsfly.wingify(options) is invalid.'],
    'no code': ['No code', 'jsfly.wingify() was called without supplying a function.'],
    'no function': ['No function', 'Parameter "code" in jsfly.wingify(code) must be a function.'],
    'nostring function': ['No string code', 'The name/tag/options.name parameters supplied to jsfly.wingify(function) must be a string.'],
    'unnamed function': ['Unnamed code', 'The function supplied to jsfly.wingify(function) must be a named function or have a tag attribute.'],

    // 'wrong host': ['Wrong host', 'The "host" provided to jsfly.createServer(host, ...) is invalid.'],
    'wrong port': ['Wrong port', 'The "port" provided to jsfly.createServer(port) is invalid.'],
    'wrong onReady': ['Wrong callback', 'Parameter "onReady" provided to jsfly.createServer(..., onReady) must be a function.']

    //'new function': ['New Function', 'jsfly.wingify() must be an object.']
};

/** MODULE INTERFACE
 *@method {function} -
 */
module.exports.throwNew = function returnExceptionObject(exceptionName) {
    var exception = EXCEPTIONS[exceptionName] || EXCEPTIONS['default'];

    return {
        name:  exception[0],
        message: exception[1]
    }
};
<|endoftext|>


<commit_before>/**
 * GoogleChart component.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import debounce from 'lodash/debounce';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useEffect, useState, useRef, useCallback } from '@wordpress/element';

/**
 * Internal dependencies
 */
import ProgressBar from './ProgressBar';

let chartLoadPromise;

async function loadCharts() {
	if ( chartLoadPromise ) {
		return chartLoadPromise;
	}

	// Inject the script if not already loaded and resolve on load.
	if ( ! global.google || ! global.google.charts ) {
		const script = document.createElement( 'script' );
		script.type = 'text/javascript';

		chartLoadPromise = new Promise( ( resolve ) => {
			script.onload = resolve;
			// Add the script to the DOM
			global.document.head.appendChild( script );
			// Set the `src` to begin transport
			script.src = 'https://www.gstatic.com/charts/loader.js';
		} );
	} else {
		// Charts is already available - resolve immediately.
		chartLoadPromise = Promise.resolve();
	}

	return chartLoadPromise;
}

export default function GoogleChart( props ) {
	const {
		chartType,
		className,
		data,
		loadCompressed,
		loadHeight,
		loadSmall,
		loadText,
		options,
		selectedStats,
		singleStat,
	} = props;

	const chartRef = useRef( null );
	const [ chart, setChart ] = useState( null );
	const [ loading, setLoading ] = useState( true );

	const drawChart = useCallback( () => {
		let dataTable = global.google?.visualization?.arrayToDataTable?.( data );
		if ( dataTable ) {
			if ( selectedStats.length > 0 ) {
				dataTable = new global.google.visualization.DataView( dataTable );
				if ( ! singleStat ) {
					dataTable.setColumns( [
						0,
						...selectedStats.map( ( stat ) => stat + 1 ),
					] );
				}
			}

			chart.draw( dataTable, options );
		}
	}, [ chart, data, singleStat, selectedStats ] );

	useEffect( () => {
		loadCharts().then( () => {
			global.google.charts.load( 'current', {
				packages: [ 'corechart' ],
				callback: () => {
					setLoading( false );
				},
			} );
		} );

		const resize = debounce( drawChart, 100 );
		global.addEventListener( 'resize', resize );

		return () => {
			global.removeEventListener( 'resize', resize );
		};
	}, [] );

	// Create a new chart when the library is loaded.
	useEffect( () => {
		if ( ! loading && chartRef.current && global.google ) {
			const googleChart = 'pie' === chartType
				? new global.google.visualization.PieChart( chartRef.current )
				: new global.google.visualization.LineChart( chartRef.current );
			setChart( googleChart );
		}
	}, [ loading, !! chartRef.current, chartType ] );

	// Draw the chart whenever one of these properties has changed.
	useEffect( () => {
		if ( chart ) {
			drawChart();
		}
	}, [
		chart,
		selectedStats,
		options,
		singleStat,
	] );

	return (

					{ loading && (

							{ loadText && (

{ __( 'Loading chart…', 'google-site-kit' ) }

							) }

							<ProgressBar
								className={ className }
								small={ loadSmall }
								compress={ loadCompressed }
								height={ loadHeight }
							/>

					) }

	);
}

GoogleChart.propTypes = {
	chartType: PropTypes.string,
	className: PropTypes.string,
	data: PropTypes.arrayOf( PropTypes.array ),
	loadCompressed: PropTypes.bool,
	loadHeight: PropTypes.number,
	loadSmall: PropTypes.bool,
	loadText: PropTypes.bool,
	options: PropTypes.object.isRequired,
	selectedStats: PropTypes.array,
	singleStat: PropTypes.bool,
};

GoogleChart.defaultProps = {
	chartType: 'line',
	className: '',
	data: [],
	loadCompressed: false,
	loadSmall: false,
	loadHeight: null,
	loadText: true,
	selectedStats: [],
	singleStat: true,
};
<commit_msg>Update assets/js/components/GoogleChart.js<commit_after>/**
 * GoogleChart component.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import debounce from 'lodash/debounce';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useEffect, useState, useRef, useCallback } from '@wordpress/element';

/**
 * Internal dependencies
 */
import ProgressBar from './ProgressBar';

let chartLoadPromise;

async function loadCharts() {
	if ( chartLoadPromise ) {
		return chartLoadPromise;
	}

	// Inject the script if not already loaded and resolve on load.
	if ( ! global.google || ! global.google.charts ) {
		const script = document.createElement( 'script' );
		script.type = 'text/javascript';

		chartLoadPromise = new Promise( ( resolve ) => {
			script.onload = resolve;
			// Add the script to the DOM
			global.document.head.appendChild( script );
			// Set the `src` to begin transport
			script.src = 'https://www.gstatic.com/charts/loader.js';
		} );
	} else {
		// Charts is already available - resolve immediately.
		chartLoadPromise = Promise.resolve();
	}

	return chartLoadPromise;
}

export default function GoogleChart( props ) {
	const {
		chartType,
		className,
		data,
		loadCompressed,
		loadHeight,
		loadSmall,
		loadText,
		options,
		selectedStats,
		singleStat,
	} = props;

	const chartRef = useRef( null );
	const [ chart, setChart ] = useState( null );
	const [ loading, setLoading ] = useState( true );

	const drawChart = useCallback( () => {
		let dataTable = global.google?.visualization?.arrayToDataTable?.( data );
		if ( ! dataTable ) {
			return;
		}
		if ( selectedStats.length > 0 ) {
			const dataView = new global.google.visualization.DataView( dataTable );
			if ( ! singleStat ) {
				dataView.setColumns(
					[ 0, ...selectedStats.map( ( stat ) => stat + 1 ) ]
				);
			}
			dataTable = dataView;
		}
		chart.draw( dataTable, options );
	}, [ chart, data, singleStat, selectedStats ] );

	useEffect( () => {
		loadCharts().then( () => {
			global.google.charts.load( 'current', {
				packages: [ 'corechart' ],
				callback: () => {
					setLoading( false );
				},
			} );
		} );

		const resize = debounce( drawChart, 100 );
		global.addEventListener( 'resize', resize );

		return () => {
			global.removeEventListener( 'resize', resize );
		};
	}, [] );

	// Create a new chart when the library is loaded.
	useEffect( () => {
		if ( ! loading && chartRef.current && global.google ) {
			const googleChart = 'pie' === chartType
				? new global.google.visualization.PieChart( chartRef.current )
				: new global.google.visualization.LineChart( chartRef.current );
			setChart( googleChart );
		}
	}, [ loading, !! chartRef.current, chartType ] );

	// Draw the chart whenever one of these properties has changed.
	useEffect( () => {
		if ( chart ) {
			drawChart();
		}
	}, [
		chart,
		selectedStats,
		options,
		singleStat,
	] );

	return (

					{ loading && (

							{ loadText && (

{ __( 'Loading chart…', 'google-site-kit' ) }

							) }

							<ProgressBar
								className={ className }
								small={ loadSmall }
								compress={ loadCompressed }
								height={ loadHeight }
							/>

					) }

	);
}

GoogleChart.propTypes = {
	chartType: PropTypes.string,
	className: PropTypes.string,
	data: PropTypes.arrayOf( PropTypes.array ),
	loadCompressed: PropTypes.bool,
	loadHeight: PropTypes.number,
	loadSmall: PropTypes.bool,
	loadText: PropTypes.bool,
	options: PropTypes.object.isRequired,
	selectedStats: PropTypes.array,
	singleStat: PropTypes.bool,
};

GoogleChart.defaultProps = {
	chartType: 'line',
	className: '',
	data: [],
	loadCompressed: false,
	loadSmall: false,
	loadHeight: null,
	loadText: true,
	selectedStats: [],
	singleStat: true,
};
<|endoftext|>


<commit_before>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// @brief Foxx Mocha integration
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2015 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Alan Plum
/// @author Copyright 2015, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var mocha = require('mocha');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

function Mocha() {
  this.suite = new mocha.Suite('', new mocha.Context());
  this.options = {};
  Object.keys(mocha.interfaces).forEach(function (key) {
    mocha.interfaces[key](this.suite);
  }.bind(this));
  EventEmitter.call(this);
}
util.inherits(Mocha, EventEmitter);

Mocha.prototype.run = function () {
  var runner = new mocha.Runner(this.suite, false);
  var reporter = new mocha.reporters.JSON(runner, this.options);
  runner.run();
  return reporter.stats;
};

Mocha.prototype.loadFiles = function (app) {
  var files = app._manifest.tests ? app._manifest.tests.slice() : [];
  files.forEach(function (file) {
    var context = {};
    this.suite.emit('pre-require', context, file, this);
    this.suite.emit('require', app.loadAppScript(file, {context: context}), file, this);
    this.suite.emit('post-require', global, file, this);
  }.bind(this));
};

exports.run = function (app) {
  var m = new Mocha();
  m.loadFiles(app);
  return m.run();
};<commit_msg>No need to emit.<commit_after>'use strict';

////////////////////////////////////////////////////////////////////////////////
/// @brief Foxx Mocha integration
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2015 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Alan Plum
/// @author Copyright 2015, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var mocha = require('mocha');

function Mocha() {
  this.suite = new mocha.Suite('', new mocha.Context());
  this.options = {};
  Object.keys(mocha.interfaces).forEach(function (key) {
    mocha.interfaces[key](this.suite);
  }.bind(this));
}

Mocha.prototype.run = function () {
  var runner = new mocha.Runner(this.suite, false);
  var reporter = new mocha.reporters.JSON(runner, this.options);
  runner.run();
  return reporter.stats;
};

Mocha.prototype.loadFiles = function (app) {
  var files = app._manifest.tests ? app._manifest.tests.slice() : [];
  files.forEach(function (file) {
    var context = {};
    this.suite.emit('pre-require', context, file, this);
    this.suite.emit('require', app.loadAppScript(file, {context: context}), file, this);
    this.suite.emit('post-require', global, file, this);
  }.bind(this));
};

exports.run = function (app) {
  var m = new Mocha();
  m.loadFiles(app);
  return m.run();
};<|endoftext|>


<commit_before>/**
 * @fileOverview 自定义的 shape
 * @author dxq613@gmail.com
 * @author sima.zhang1990@gmail.com
 */

const Util = require('../../util');
const Shape = require('./shape');
const Global = require('../../global');

function _parseValue(value) {
  if (!Util.isArray(value)) {
    value = [ value ];
  }
  const min = value[0]; // 最小值
  const max = value[value.length - 1]; // 最大值
  const min1 = value.length > 1 ? value[1] : min;
  const max1 = value.length > 3 ? value[3] : max;
  const median = value.length > 2 ? value[2] : min1;

  return {
    min, // 最小值
    max, // 最大值
    min1,
    max1,
    median
  };
}

function addPoints(from, to) {
  Util.each(from, function(subArr) {
    to.push({
      x: subArr[0],
      y: subArr[1]
    });
  });
}

function getAttrs(cfg) {
  const defaultAttrs = Global.shape.schema;
  const attrs = Util.mix({}, defaultAttrs, {
    stroke: cfg.color,
    strokeOpacity: cfg.opacity
  }, cfg.style);
  return attrs;
}

function getFillAttrs(cfg) {
  const defaultAttrs = Global.shape.schema;
  const attrs = Util.mix({}, defaultAttrs, {
    fill: cfg.color,
    stroke: cfg.color,
    fillOpacity: cfg.opacity
  }, cfg.style);
  return attrs;
}

function getBoxPoints(x, y, width) {
  const points = [];
  let pointsArray;
  let obj;
  if (Util.isArray(y)) { // 2维
    obj = _parseValue(y);
    pointsArray = [
      [ x - width / 2, obj.max ],
      [ x + width / 2, obj.max ],
      [ x, obj.max ],
      [ x, obj.max1 ],
      [ x - width / 2, obj.min1 ],
      [ x - width / 2, obj.max1 ],
      [ x + width / 2, obj.max1 ],
      [ x + width / 2, obj.min1 ],
      [ x, obj.min1 ],
      [ x, obj.min ],
      [ x - width / 2, obj.min ],
      [ x + width / 2, obj.min ],
      [ x - width / 2, obj.median ],
      [ x + width / 2, obj.median ]
    ];
  } else { // 只有一个维度
    y = y || 0.5;
    obj = _parseValue(x);
    pointsArray = [
      [ obj.min, y - width / 2 ],
      [ obj.min, y + width / 2 ],
      [ obj.min, y ],
      [ obj.min1, y ],
      [ obj.min1, y - width / 2 ],
      [ obj.min1, y + width / 2 ],
      [ obj.max1, y + width / 2 ],
      [ obj.max1, y - width / 2 ],
      [ obj.max1, y ],
      [ obj.max, y ],
      [ obj.max, y - width / 2 ],
      [ obj.max, y + width / 2 ],
      [ obj.median, y - width / 2 ],
      [ obj.median, y + width / 2 ]
    ];
  }
  addPoints(pointsArray, points);
  return points;
}

function _sortValue(value) {
  if (!Util.isArray(value)) {
    value = [ value ];
  }
  // 从大到小排序
  const sorted = value.sort(function(a, b) {
    return a < b ? 1 : -1;
  });

  const length = sorted.length;
  if (length < 4) {
    const min = sorted[length - 1];
    for (let i = 0; i < (4 - length); i++) {
      sorted.push(min);
    }
  }

  return sorted;
}

// 获取K线图的points
function getCandlePoints(x, y, width) {
  const yValues = _sortValue(y);
  const points = [{
    x,
    y: yValues[0]
  }, {
    x,
    y: yValues[1]
  }, {
    x: x - width / 2,
    y: yValues[2]
  }, {
    x: x - width / 2,
    y: yValues[1]
  }, {
    x: x + width / 2,
    y: yValues[1]
  }, {
    x: x + width / 2,
    y: yValues[2]
  }, {
    x,
    y: yValues[2]
  }, {
    x,
    y: yValues[3]
  }]; // 按照顺时针连接
  return points;
}

function getBoxPath(points) {
  const path = [
    [ 'M', points[0].x, points[0].y ],
    [ 'L', points[1].x, points[1].y ],
    [ 'M', points[2].x, points[2].y ],
    [ 'L', points[3].x, points[3].y ],
    [ 'M', points[4].x, points[4].y ],
    [ 'L', points[5].x, points[5].y ],
    [ 'L', points[6].x, points[6].y ],
    [ 'L', points[7].x, points[7].y ],
    [ 'L', points[4].x, points[4].y ], // 封闭 z
    [ 'Z' ],
    [ 'M', points[8].x, points[8].y ],
    [ 'L', points[9].x, points[9].y ],
    [ 'M', points[10].x, points[10].y ],
    [ 'L', points[11].x, points[11].y ],
    [ 'M', points[12].x, points[12].y ],
    [ 'L', points[13].x, points[13].y ]
  ];
  return path;
}

function getCandlePath(points) {
  const path = [
    [ 'M', points[0].x, points[0].y ],
    [ 'L', points[1].x, points[1].y ],
    [ 'M', points[2].x, points[2].y ],
    [ 'L', points[3].x, points[3].y ],
    [ 'L', points[4].x, points[4].y ],
    [ 'L', points[5].x, points[5].y ],
    [ 'Z' ],
    [ 'M', points[6].x, points[6].y ],
    [ 'L', points[7].x, points[7].y ]
  ];
  return path;
}

const Schema = Shape.registerFactory('schema', {
  defaultShapeType: '',
  getActiveCfg(type, cfg) {
    if (type === 'box') {
      const lineWidth = cfg.lineWidth || 1;
      return {
        lineWidth: lineWidth + 1
      };
    }
    const opacity = cfg.fillOpacity || cfg.opacity || 1;
    return {
      fillOpacity: opacity - 0.15,
      strokeOpacity: opacity - 0.15
    };
  },
  getSelectedCfg(type, cfg) {
    if (cfg && cfg.style) {
      return cfg.style;
    }
    return this.getActiveCfg(type, cfg);
  }
});

// 箱线图
Shape.registerShape('schema', 'box', {
  getPoints(pointInfo) {
    return getBoxPoints(pointInfo.x, pointInfo.y, pointInfo.size);
  },
  draw(cfg, container) {
    const attrs = getAttrs(cfg);
    let path = getBoxPath(cfg.points);
    path = this.parsePath(path);
    return container.addShape('path', {
      attrs: Util.mix(attrs, {
        path
      })
    });
  },
  getMarkerCfg(cfg) {
    return {
      symbol(x, y, r, ctx) {
        const yValues = [ y - 6, y - 3, y, y + 3, y + 6 ];
        const points = getBoxPoints(x, yValues, r);
        ctx.moveTo(points[0].x + 1, points[0].y);
        ctx.lineTo(points[1].x - 1, points[1].y);
        ctx.moveTo(points[2].x, points[2].y);
        ctx.lineTo(points[3].x, points[3].y);
        ctx.moveTo(points[4].x, points[4].y);
        ctx.lineTo(points[5].x, points[5].y);
        ctx.lineTo(points[6].x, points[6].y);
        ctx.lineTo(points[7].x, points[7].y);
        ctx.lineTo(points[4].x, points[4].y);
        ctx.closePath();
        ctx.moveTo(points[8].x, points[8].y);
        ctx.lineTo(points[9].x, points[9].y);
        ctx.moveTo(points[10].x + 1, points[10].y);
        ctx.lineTo(points[11].x - 1, points[11].y);
        ctx.moveTo(points[12].x, points[12].y);
        ctx.lineTo(points[13].x, points[13].y);
      },
      radius: 6,
      lineWidth: 1,
      stroke: cfg.color
    };
  }
});

// K线
Shape.registerShape('schema', 'candle', {
  getPoints(pointInfo) {
    return getCandlePoints(pointInfo.x, pointInfo.y, pointInfo.size);
  },
  draw(cfg, container) {
    const attrs = getFillAttrs(cfg);
    let path = getCandlePath(cfg.points);
    path = this.parsePath(path);
    return container.addShape('path', {
      attrs: Util.mix(attrs, {
        path
      })
    });
  },
  getMarkerCfg(cfg) {
    return {
      symbol(x, y, r, ctx) {
        y = [ y + 7.5, y + 3, y - 3, y - 7.5 ];
        const points = getCandlePoints(x, y, r);
        ctx.moveTo(points[0].x, points[0].y);
        ctx.lineTo(points[1].x, points[1].y);
        ctx.moveTo(points[2].x, points[2].y);
        ctx.lineTo(points[3].x, points[3].y);
        ctx.lineTo(points[4].x, points[4].y);
        ctx.lineTo(points[5].x, points[5].y);
        ctx.closePath();
        ctx.moveTo(points[6].x, points[6].y);
        ctx.lineTo(points[7].x, points[7].y);
      },
      lineWidth: 1,
      stroke: cfg.color,
      fill: cfg.color,
      radius: 6
    };
  }
});

module.exports = Schema;
<commit_msg>fix: pass path array instead of manipulating context when defining Marker<commit_after>/**
 * @fileOverview 自定义的 shape
 * @author dxq613@gmail.com
 * @author sima.zhang1990@gmail.com
 */

const Util = require('../../util');
const Shape = require('./shape');
const Global = require('../../global');

function _parseValue(value) {
  if (!Util.isArray(value)) {
    value = [ value ];
  }
  const min = value[0]; // 最小值
  const max = value[value.length - 1]; // 最大值
  const min1 = value.length > 1 ? value[1] : min;
  const max1 = value.length > 3 ? value[3] : max;
  const median = value.length > 2 ? value[2] : min1;

  return {
    min, // 最小值
    max, // 最大值
    min1,
    max1,
    median
  };
}

function addPoints(from, to) {
  Util.each(from, function(subArr) {
    to.push({
      x: subArr[0],
      y: subArr[1]
    });
  });
}

function getAttrs(cfg) {
  const defaultAttrs = Global.shape.schema;
  const attrs = Util.mix({}, defaultAttrs, {
    stroke: cfg.color,
    strokeOpacity: cfg.opacity
  }, cfg.style);
  return attrs;
}

function getFillAttrs(cfg) {
  const defaultAttrs = Global.shape.schema;
  const attrs = Util.mix({}, defaultAttrs, {
    fill: cfg.color,
    stroke: cfg.color,
    fillOpacity: cfg.opacity
  }, cfg.style);
  return attrs;
}

function getBoxPoints(x, y, width) {
  const points = [];
  let pointsArray;
  let obj;
  if (Util.isArray(y)) { // 2维
    obj = _parseValue(y);
    pointsArray = [
      [ x - width / 2, obj.max ],
      [ x + width / 2, obj.max ],
      [ x, obj.max ],
      [ x, obj.max1 ],
      [ x - width / 2, obj.min1 ],
      [ x - width / 2, obj.max1 ],
      [ x + width / 2, obj.max1 ],
      [ x + width / 2, obj.min1 ],
      [ x, obj.min1 ],
      [ x, obj.min ],
      [ x - width / 2, obj.min ],
      [ x + width / 2, obj.min ],
      [ x - width / 2, obj.median ],
      [ x + width / 2, obj.median ]
    ];
  } else { // 只有一个维度
    y = y || 0.5;
    obj = _parseValue(x);
    pointsArray = [
      [ obj.min, y - width / 2 ],
      [ obj.min, y + width / 2 ],
      [ obj.min, y ],
      [ obj.min1, y ],
      [ obj.min1, y - width / 2 ],
      [ obj.min1, y + width / 2 ],
      [ obj.max1, y + width / 2 ],
      [ obj.max1, y - width / 2 ],
      [ obj.max1, y ],
      [ obj.max, y ],
      [ obj.max, y - width / 2 ],
      [ obj.max, y + width / 2 ],
      [ obj.median, y - width / 2 ],
      [ obj.median, y + width / 2 ]
    ];
  }
  addPoints(pointsArray, points);
  return points;
}

function _sortValue(value) {
  if (!Util.isArray(value)) {
    value = [ value ];
  }
  // 从大到小排序
  const sorted = value.sort(function(a, b) {
    return a < b ? 1 : -1;
  });

  const length = sorted.length;
  if (length < 4) {
    const min = sorted[length - 1];
    for (let i = 0; i < (4 - length); i++) {
      sorted.push(min);
    }
  }

  return sorted;
}

// 获取K线图的points
function getCandlePoints(x, y, width) {
  const yValues = _sortValue(y);
  const points = [{
    x,
    y: yValues[0]
  }, {
    x,
    y: yValues[1]
  }, {
    x: x - width / 2,
    y: yValues[2]
  }, {
    x: x - width / 2,
    y: yValues[1]
  }, {
    x: x + width / 2,
    y: yValues[1]
  }, {
    x: x + width / 2,
    y: yValues[2]
  }, {
    x,
    y: yValues[2]
  }, {
    x,
    y: yValues[3]
  }]; // 按照顺时针连接
  return points;
}

function getBoxPath(points) {
  const path = [
    [ 'M', points[0].x, points[0].y ],
    [ 'L', points[1].x, points[1].y ],
    [ 'M', points[2].x, points[2].y ],
    [ 'L', points[3].x, points[3].y ],
    [ 'M', points[4].x, points[4].y ],
    [ 'L', points[5].x, points[5].y ],
    [ 'L', points[6].x, points[6].y ],
    [ 'L', points[7].x, points[7].y ],
    [ 'L', points[4].x, points[4].y ], // 封闭 z
    [ 'Z' ],
    [ 'M', points[8].x, points[8].y ],
    [ 'L', points[9].x, points[9].y ],
    [ 'M', points[10].x, points[10].y ],
    [ 'L', points[11].x, points[11].y ],
    [ 'M', points[12].x, points[12].y ],
    [ 'L', points[13].x, points[13].y ]
  ];
  return path;
}

function getCandlePath(points) {
  const path = [
    [ 'M', points[0].x, points[0].y ],
    [ 'L', points[1].x, points[1].y ],
    [ 'M', points[2].x, points[2].y ],
    [ 'L', points[3].x, points[3].y ],
    [ 'L', points[4].x, points[4].y ],
    [ 'L', points[5].x, points[5].y ],
    [ 'Z' ],
    [ 'M', points[6].x, points[6].y ],
    [ 'L', points[7].x, points[7].y ]
  ];
  return path;
}

const Schema = Shape.registerFactory('schema', {
  defaultShapeType: '',
  getActiveCfg(type, cfg) {
    if (type === 'box') {
      const lineWidth = cfg.lineWidth || 1;
      return {
        lineWidth: lineWidth + 1
      };
    }
    const opacity = cfg.fillOpacity || cfg.opacity || 1;
    return {
      fillOpacity: opacity - 0.15,
      strokeOpacity: opacity - 0.15
    };
  },
  getSelectedCfg(type, cfg) {
    if (cfg && cfg.style) {
      return cfg.style;
    }
    return this.getActiveCfg(type, cfg);
  }
});

// 箱线图
Shape.registerShape('schema', 'box', {
  getPoints(pointInfo) {
    return getBoxPoints(pointInfo.x, pointInfo.y, pointInfo.size);
  },
  draw(cfg, container) {
    const attrs = getAttrs(cfg);
    let path = getBoxPath(cfg.points);
    path = this.parsePath(path);
    return container.addShape('path', {
      attrs: Util.mix(attrs, {
        path
      })
    });
  },
  getMarkerCfg(cfg) {
    return {
      symbol(x, y, r) {
        const yValues = [ y - 6, y - 3, y, y + 3, y + 6 ];
        const points = getBoxPoints(x, yValues, r);
        return [
          [ 'M', points[0].x + 1, points[0].y ],
          [ 'L', points[1].x - 1, points[1].y ],
          [ 'M', points[2].x, points[2].y ],
          [ 'L', points[3].x, points[3].y ],
          [ 'M', points[4].x, points[4].y ],
          [ 'L', points[5].x, points[5].y ],
          [ 'L', points[6].x, points[6].y ],
          [ 'L', points[7].x, points[7].y ],
          [ 'L', points[4].x, points[4].y ],
          [ 'Z' ],
          [ 'M', points[8].x, points[8].y ],
          [ 'L', points[9].x, points[9].y ],
          [ 'M', points[10].x + 1, points[10].y ],
          [ 'L', points[11].x - 1, points[11].y ],
          [ 'M', points[12].x, points[12].y ],
          [ 'L', points[13].x, points[13].y ]
        ];
      },
      radius: 6,
      lineWidth: 1,
      stroke: cfg.color
    };
  }
});

// K线
Shape.registerShape('schema', 'candle', {
  getPoints(pointInfo) {
    return getCandlePoints(pointInfo.x, pointInfo.y, pointInfo.size);
  },
  draw(cfg, container) {
    const attrs = getFillAttrs(cfg);
    let path = getCandlePath(cfg.points);
    path = this.parsePath(path);
    return container.addShape('path', {
      attrs: Util.mix(attrs, {
        path
      })
    });
  },
  getMarkerCfg(cfg) {
    return {
      symbol(x, y, r) {
        y = [ y + 7.5, y + 3, y - 3, y - 7.5 ];
        const points = getCandlePoints(x, y, r);
        return [
          [ 'M', points[0].x, points[0].y ],
          [ 'L', points[1].x, points[1].y ],
          [ 'M', points[2].x, points[2].y ],
          [ 'L', points[3].x, points[3].y ],
          [ 'L', points[4].x, points[4].y ],
          [ 'L', points[5].x, points[5].y ],
          [ 'Z' ],
          [ 'M', points[6].x, points[6].y ],
          [ 'L', points[7].x, points[7].y ]
        ];
      },
      lineWidth: 1,
      stroke: cfg.color,
      fill: cfg.color,
      radius: 6
    };
  }
});

module.exports = Schema;
<|endoftext|>


<commit_before>import yargs from "yargs"
import fs from "fs"
import pem from "pem"

export default (args = process.argv) => {
	var argsDefinition = yargs(args)
		.usage('Usage: $0 <command> [options]')
		.option("routes-file", {
			type: "string",
			describe: "The routes file to load. Default is 'routes.json'.",
		})
		.option("p", {
			alias: "port",
			describe: "Port to start listening for react-server. Default is 3000.",
			type: "number",
		})
		.option("host", {
			describe: "Hostname to start listening for react-server",
			type: "string",
		})
		.option("js-port", {
			describe: "Port to start listening for react-server's JavaScript. Default is 3001.",
			type: "number",
		})
		.option("bind-ip", {
			describe: "IP address to bind to. Default: 0.0.0.0 (any)",
			type: "string",
		})
		.option("https", {
			describe: "If true, the server will start up using https with a self-signed certificate. Note that browsers do not trust self-signed certificates by default, so you will have to click through some warning screens. This is a quick and dirty way to test HTTPS, but it has some limitations and should never be used in production. Requires OpenSSL to be installed. Default is false.",
			default: undefined,
			type: "boolean",
		})
		.option("https-key", {
			describe: "Start the server using HTTPS with this private key file in PEM format. Requires https-cert to be set as well. Default is none.",
			type: "string",
		})
		.option("https-cert", {
			describe: "Start the server using HTTPS with this cert file in PEM format. Requires https-key to be set as well. Default is none.",
			type: "string",
		})
		.option("https-ca", {
			describe: "Start the server using HTTPS with this certificate authority file in PEM format. Also requires https-key and https-cert to start the server. Default is none.",
			type: "string",
		})
		.option("https-pfx", {
			describe: "Start the server using HTTPS with this file containing the private key, certificate and CA certs of the server in PFX or PKCS12 format. Mutually exclusive with https-key, https-cert, and https-ca. Default is none.",
			type: "string",
		})
		.option("https-passphrase", {
			describe: "A passphrase for the private key or pfx. Requires https-key or https-pfx to be set. Default is none.",
			type: "string",
		})
		.option("h", {
			alias: "hot",
			describe: "Load the app so that it can be hot reloaded in the browser. Default is false in production mode, true otherwise.",
			// we use undefined as the default because unlike other types, booleans
			// default to "false", making it impossible to distinguish between not
			// setting the option at the command line and setting --option=false.
			default: undefined,
			type: "boolean",
		})
		.option("m", {
			alias: "minify",
			describe: "Optimize client JS when option is present. Takes a bit longer to compile. Default is true in production mode, false otherwise.",
			default: undefined,
			type: "boolean",
		})
		.option("custom-middleware-path", {
			describe: "Path to custom middleware function file. If it is not defined default setup will be applied.",
			default: undefined,
			type: "string",
		})
		.option("long-term-caching", {
			describe: "Use long-term cache headers for the static JS & CSS files. Default is true in production mode, false otherwise.",
			default: undefined,
			type: "boolean",
		})
		.option("log-level", {
			describe: "Set the severity level for the logs being reported. Values are, in ascending order of severity: 'debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency'. Default is 'notice' in production mode, 'debug' otherwise.",
			type: "string",
		})
		.option("timing-log-level", {
			describe: "Set the severity level for the timing logs. Values are, in ascending order of verbosity: 'none', 'slow', 'fine', 'fast. Default is 'none' in production mode, 'fast' otherwise.",
			type: "string",
		})
		.option("gauge-log-level", {
			describe: "Set the severity level for the gauge logs. Values are, in ascending order of severity: 'no', 'hi', 'lo', 'ok'. Default is 'no' in production mode, 'ok' otherwise.",
			type: "string",
		})
		.option("compile-only", {
			describe: "Compile the client JavaScript only, and don't start any servers. This is what you want to do if you are building the client JavaScript to be hosted on a CDN. Unless you have a very specific reason, it's almost alway a good idea to only do this in production mode. Defaults to false.",
			default: undefined,
			type: "boolean",
		})
		.option("js-url", {
			describe: "A URL base for the pre-compiled client JavaScript. Setting a value for jsurl means that react-server-cli will not compile the client JavaScript at all, and it will not serve up any JavaScript. Obviously, this means that --jsurl overrides all of the options related to JavaScript compilation: --hot, --minify, and --bundleperroute.",
			type: "string",
		})
		.option("stats", {
			describe: "Output webpack stats to __clientTemp/build/stats.json.  Recommended for use with webpack-bundle-size-analyzer.",
			default: false,
			type: "boolean",
		})
		.version(function() {
			return require('../package').version;
		})
		.alias('v', 'version')
		.help('?')
		.alias('?', 'help')
		.demand(0)

	const commands = {
		"start"    : "Start the server",
		"compile"  : "Compile static assets",
		"init"     : "Initialize a React Server site",
		"add-page" : "Add a page to an existing site",
	}

	Object.keys(commands)
		.forEach(k => argsDefinition = argsDefinition.command(k, commands[k]));

	var parsedArgs = argsDefinition.argv;

	parsedArgs.command = parsedArgs._[2];

	if (!commands[parsedArgs.command]) {
		argsDefinition.showHelp();
		if (parsedArgs.command) {
			console.log("Invalid command: " + parsedArgs.command);
		}
		process.exit(1); // eslint-disable-line no-process-exit
	}

	// we remove all the options that have undefined as their value; those are the
	// ones that weren't on the command line, and we don't want them to override
	// defaults or config files.
	return sslize(removeUndefinedValues(parsedArgs));

}

const sslize = async argv => {

	const {
		https,
		httpsKey,
		httpsCert,
		httpsCa,
		httpsPfx,
		httpsPassphrase,
	} = argv;

	if (https || (httpsKey && httpsCert) || httpsPfx) {
		if ((httpsKey && httpsCert) || httpsPfx) {
			argv.httpsOptions = {
				key: httpsKey ? fs.readFileSync(httpsKey) : undefined,
				cert: httpsCert ? fs.readFileSync(httpsCert) : undefined,
				ca: httpsCa ? fs.readFileSync(httpsCa) : undefined,
				pfx: httpsPfx ? fs.readFileSync(httpsPfx) : undefined,
				passphrase: httpsPassphrase,
			};
		} else {
			argv.httpsOptions = await new Promise((resolve, reject) => {
				pem.createCertificate({ days: 1, selfSigned: true }, (err, keys) => {
					if (err) {
						reject(err);
					}
					resolve({ key: keys.serviceKey, cert: keys.certificate });
				});
			});
		}
	} else {
		argv.httpsOptions = false;
	}

	if ((httpsKey || httpsCert || httpsCa) && httpsPfx) {
		throw new Error("If you set https.pfx, you can't set https.key, https.cert, or https.ca.");
	}

	return argv;
}

const removeUndefinedValues = (input) => {
	const result = Object.assign({}, input);

	for (let key of Object.keys(input)) {
		if (result[key] === undefined) {
			delete result[key];
		}
	}

	return result;
}
<commit_msg>Updating docs for --host<commit_after>import yargs from "yargs"
import fs from "fs"
import pem from "pem"

export default (args = process.argv) => {
	var argsDefinition = yargs(args)
		.usage('Usage: $0 <command> [options]')
		.option("routes-file", {
			type: "string",
			describe: "The routes file to load. Default is 'routes.json'.",
		})
		.option("p", {
			alias: "port",
			describe: "Port to start listening for react-server. Default is 3000.",
			type: "number",
		})
		.option("host", {
			describe: "The public host name combined with js-port used to construct URLs for static content. Ignored when js-url is set.",
			type: "string",
		})
		.option("js-port", {
			describe: "Port to start listening for react-server's JavaScript. Default is 3001.",
			type: "number",
		})
		.option("bind-ip", {
			describe: "IP address to bind to. Default: 0.0.0.0 (any)",
			type: "string",
		})
		.option("https", {
			describe: "If true, the server will start up using https with a self-signed certificate. Note that browsers do not trust self-signed certificates by default, so you will have to click through some warning screens. This is a quick and dirty way to test HTTPS, but it has some limitations and should never be used in production. Requires OpenSSL to be installed. Default is false.",
			default: undefined,
			type: "boolean",
		})
		.option("https-key", {
			describe: "Start the server using HTTPS with this private key file in PEM format. Requires https-cert to be set as well. Default is none.",
			type: "string",
		})
		.option("https-cert", {
			describe: "Start the server using HTTPS with this cert file in PEM format. Requires https-key to be set as well. Default is none.",
			type: "string",
		})
		.option("https-ca", {
			describe: "Start the server using HTTPS with this certificate authority file in PEM format. Also requires https-key and https-cert to start the server. Default is none.",
			type: "string",
		})
		.option("https-pfx", {
			describe: "Start the server using HTTPS with this file containing the private key, certificate and CA certs of the server in PFX or PKCS12 format. Mutually exclusive with https-key, https-cert, and https-ca. Default is none.",
			type: "string",
		})
		.option("https-passphrase", {
			describe: "A passphrase for the private key or pfx. Requires https-key or https-pfx to be set. Default is none.",
			type: "string",
		})
		.option("h", {
			alias: "hot",
			describe: "Load the app so that it can be hot reloaded in the browser. Default is false in production mode, true otherwise.",
			// we use undefined as the default because unlike other types, booleans
			// default to "false", making it impossible to distinguish between not
			// setting the option at the command line and setting --option=false.
			default: undefined,
			type: "boolean",
		})
		.option("m", {
			alias: "minify",
			describe: "Optimize client JS when option is present. Takes a bit longer to compile. Default is true in production mode, false otherwise.",
			default: undefined,
			type: "boolean",
		})
		.option("custom-middleware-path", {
			describe: "Path to custom middleware function file. If it is not defined default setup will be applied.",
			default: undefined,
			type: "string",
		})
		.option("long-term-caching", {
			describe: "Use long-term cache headers for the static JS & CSS files. Default is true in production mode, false otherwise.",
			default: undefined,
			type: "boolean",
		})
		.option("log-level", {
			describe: "Set the severity level for the logs being reported. Values are, in ascending order of severity: 'debug', 'info', 'notice', 'warning', 'error', 'critical', 'alert', 'emergency'. Default is 'notice' in production mode, 'debug' otherwise.",
			type: "string",
		})
		.option("timing-log-level", {
			describe: "Set the severity level for the timing logs. Values are, in ascending order of verbosity: 'none', 'slow', 'fine', 'fast. Default is 'none' in production mode, 'fast' otherwise.",
			type: "string",
		})
		.option("gauge-log-level", {
			describe: "Set the severity level for the gauge logs. Values are, in ascending order of severity: 'no', 'hi', 'lo', 'ok'. Default is 'no' in production mode, 'ok' otherwise.",
			type: "string",
		})
		.option("compile-only", {
			describe: "Compile the client JavaScript only, and don't start any servers. This is what you want to do if you are building the client JavaScript to be hosted on a CDN. Unless you have a very specific reason, it's almost alway a good idea to only do this in production mode. Defaults to false.",
			default: undefined,
			type: "boolean",
		})
		.option("js-url", {
			describe: "A URL base for the pre-compiled client JavaScript. Setting a value for jsurl means that react-server-cli will not compile the client JavaScript at all, and it will not serve up any JavaScript. Obviously, this means that --jsurl overrides all of the options related to JavaScript compilation: --hot, --minify, and --bundleperroute.",
			type: "string",
		})
		.option("stats", {
			describe: "Output webpack stats to __clientTemp/build/stats.json.  Recommended for use with webpack-bundle-size-analyzer.",
			default: false,
			type: "boolean",
		})
		.version(function() {
			return require('../package').version;
		})
		.alias('v', 'version')
		.help('?')
		.alias('?', 'help')
		.demand(0)

	const commands = {
		"start"    : "Start the server",
		"compile"  : "Compile static assets",
		"init"     : "Initialize a React Server site",
		"add-page" : "Add a page to an existing site",
	}

	Object.keys(commands)
		.forEach(k => argsDefinition = argsDefinition.command(k, commands[k]));

	var parsedArgs = argsDefinition.argv;

	parsedArgs.command = parsedArgs._[2];

	if (!commands[parsedArgs.command]) {
		argsDefinition.showHelp();
		if (parsedArgs.command) {
			console.log("Invalid command: " + parsedArgs.command);
		}
		process.exit(1); // eslint-disable-line no-process-exit
	}

	// we remove all the options that have undefined as their value; those are the
	// ones that weren't on the command line, and we don't want them to override
	// defaults or config files.
	return sslize(removeUndefinedValues(parsedArgs));

}

const sslize = async argv => {

	const {
		https,
		httpsKey,
		httpsCert,
		httpsCa,
		httpsPfx,
		httpsPassphrase,
	} = argv;

	if (https || (httpsKey && httpsCert) || httpsPfx) {
		if ((httpsKey && httpsCert) || httpsPfx) {
			argv.httpsOptions = {
				key: httpsKey ? fs.readFileSync(httpsKey) : undefined,
				cert: httpsCert ? fs.readFileSync(httpsCert) : undefined,
				ca: httpsCa ? fs.readFileSync(httpsCa) : undefined,
				pfx: httpsPfx ? fs.readFileSync(httpsPfx) : undefined,
				passphrase: httpsPassphrase,
			};
		} else {
			argv.httpsOptions = await new Promise((resolve, reject) => {
				pem.createCertificate({ days: 1, selfSigned: true }, (err, keys) => {
					if (err) {
						reject(err);
					}
					resolve({ key: keys.serviceKey, cert: keys.certificate });
				});
			});
		}
	} else {
		argv.httpsOptions = false;
	}

	if ((httpsKey || httpsCert || httpsCa) && httpsPfx) {
		throw new Error("If you set https.pfx, you can't set https.key, https.cert, or https.ca.");
	}

	return argv;
}

const removeUndefinedValues = (input) => {
	const result = Object.assign({}, input);

	for (let key of Object.keys(input)) {
		if (result[key] === undefined) {
			delete result[key];
		}
	}

	return result;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

require(["jquery","sakai/sakai.api.core"], function($, sakai) {

    sakai_global.explore = function() {
    };

    sakai.api.Widgets.Container.registerForLoad("explore");
});<commit_msg>SAKIII-4203 fix browse categories dropdown<commit_after>/*
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

require(["jquery","sakai/sakai.api.core"], function($, sakai) {

    sakai_global.explore = function() {
        var doInit = function() {
            if (sakai.config.enableCategories) {
                sakai.api.Util.TemplateRenderer($("#explore_categories_template"), {}, $("#explore_categories"));
            }
        };
        doInit();
    };

    sakai.api.Widgets.Container.registerForLoad("explore");
});<|endoftext|>


<commit_before>describe('ui.grid.edit uiGridCellNavService', function() {
	var uiGridCellNavService,
		gridClassFactory,
		grid,
		uiGridConstants,
		uiGridCellNavConstants,
		$rootScope,
		$timeout;

	beforeEach(module('ui.grid.cellNav'));

	beforeEach(inject(
		function(_uiGridCellNavService_, _gridClassFactory_, $templateCache, _uiGridConstants_, _uiGridCellNavConstants_, _$rootScope_, _$timeout_) {
			uiGridCellNavService = _uiGridCellNavService_;
			gridClassFactory = _gridClassFactory_;
			uiGridConstants = _uiGridConstants_;
			uiGridCellNavConstants = _uiGridCellNavConstants_;
			$rootScope = _$rootScope_;
			$timeout = _$timeout_;

			$templateCache.put('ui-grid/uiGridCell', '<div/>');

			grid = gridClassFactory.createGrid();
			// throttled scrolling isn't working in tests for some reason
			grid.headerHeight = 0;
			grid.footerHeight = 0;
			grid.gridHeight = 20;
			grid.options.rowHeight = 30;
			grid.options.scrollDebounce = 0;
			grid.options.columnDefs = [
				{name: 'col0', allowCellFocus: true},
				{name: 'col1', allowCellFocus: false},
				{name: 'col2'}
			];

			grid.options.data = [
				{col0: 'row0col0', col1: 'row0col1', col2: 'row0col2'},
				{col0: 'row1col0', col1: 'row1col1', col2: 'row1col2'},
				{col0: 'row2col0', col1: 'row2col1', col2: 'row2col2'}
			];

			uiGridCellNavService.initializeGrid(grid);
			grid.modifyRows(grid.options.data);
		}));

	describe('public Apis function', function() {
		beforeEach(function() {
			grid.buildColumns();
		});

		it('should have getFocusedCell', function() {
			expect(grid.api.cellNav.getFocusedCell()).toBeDefined();
			expect(grid.api.cellNav.getFocusedCell()).toBe(null);
			grid.cellNav.lastRowCol = 'mockRowCol';
			expect(grid.api.cellNav.getFocusedCell()).toBe('mockRowCol');
		});
	});

	describe('cellNavColumnBuilder function', function() {
		beforeEach(function() {
			grid.buildColumns();
		});

		it('should populate allowCellFocus with defaults', function() {
			var colDef = grid.options.columnDefs[0];
			var col = grid.columns[0];
			uiGridCellNavService.cellNavColumnBuilder(colDef, col, grid.options);
			expect(col.colDef.allowCellFocus).toBe(true);

			colDef = grid.options.columnDefs[1];
			col = grid.columns[1];
			uiGridCellNavService.cellNavColumnBuilder(colDef, col, grid.options);
			expect(col.colDef.allowCellFocus).toBe(false);

			colDef = grid.options.columnDefs[2];
			col = grid.columns[2];
			uiGridCellNavService.cellNavColumnBuilder(colDef, col, grid.options);
			expect(col.colDef.allowCellFocus).toBe(true);
		});
	});

	describe('getDirection(evt)', function() {
		beforeEach(function() {
			grid.registerColumnBuilder(uiGridCellNavService.cellNavColumnBuilder);
			grid.buildColumns();
		});
		it('should navigate right on tab', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.TAB;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.RIGHT);
		});

		it('should navigate right on right arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.RIGHT;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.RIGHT);
		});

		it('should navigate left on shift tab', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.TAB;
			evt.shiftKey = true;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.LEFT);
		});

		it('should navigate left on left arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.LEFT;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.LEFT);
		});

		it('should navigate down on enter', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.ENTER;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.DOWN);
		});

		it('should navigate down on down arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.DOWN;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.DOWN);
		});

		it('should navigate up on shift enter', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.ENTER;
			evt.shiftKey = true;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.UP);
		});

		it('should navigate up on up arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.UP;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.UP);
		});

	});

	describe('scrollTo', function() {
		/*
		 * We have 11 rows (10 visible) and 11 columns (10 visible).  The column widths are
		 * 100 for the first 5, and 200 for the second 5.  Column 2 and row 2 are invisible.
		 */
		var args;
		var $scope;

		beforeEach(function() {
			var i, j, row;
			grid.options.columnDefs = [];
			for (i = 0; i < 11; i++) {
				grid.options.columnDefs.push({name: 'col' + i});
			}

			grid.options.data = [];
			for (i = 0; i < 11; i++) {
				row = {};
				for (j = 0; j < 11; j++) {
					row['col' + j] = 'test data ' + i + '_' + j;
				}
				grid.options.data.push(row);
			}

			uiGridCellNavService.initializeGrid(grid);
			grid.modifyRows(grid.options.data);

			grid.registerColumnBuilder(uiGridCellNavService.cellNavColumnBuilder);
			grid.buildColumns();

			grid.columns[2].visible = false;
			grid.rows[2].visible = false;

			grid.setVisibleColumns(grid.columns);
			grid.setVisibleRows(grid.rows);

			grid.renderContainers.body.headerHeight = 0;

			for (i = 0; i < 11; i++) {
				grid.columns[i].drawnWidth = i < 6 ? 100 : 200;
			}

			$scope = $rootScope.$new();

			args = null;
			grid.api.core.on.scrollEnd($scope, function(receivedArgs) {
				args = receivedArgs;
			});
		});

		// these have changed to use scrollToIfNecessary, which is better code
		// but it means these unit tests are now mostly checking that it is the same it used to
		// be, not that it is giving some specified result (i.e. I just updated them to what they were)
		it('should request scroll to row and column', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[4], grid.columns[4].colDef);
			});
			$timeout.flush();

			expect(args.grid).toEqual(grid);
			expect(Math.round(args.y.percentage * 10) / 10).toBe(0.4);
			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request scroll to row only - first row', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[0], null);
			});
			$timeout.flush();

			// TODO: figure out why Safari fails on this check
			if (navigator.userAgent.indexOf('Safari') === -1) {
				expect(args.y.percentage).toBeCloseTo(0.15, 0.01);
			}
		});

		it('should request scroll to row only - last row', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[10], null);
			});
			$timeout.flush();

			expect(args.y.percentage).toBeGreaterThan(0.5);
			expect(args.x).toBe(null);
		});

		it('should request scroll to row only - row 4', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[5], null);
			});
			$timeout.flush();

			expect(Math.round(args.y.percentage * 10) / 10).toEqual(0.5);
			expect(args.x).toBe(null);
		});

		it('should request scroll to column only - first column', function() {
			$timeout(function() {
				grid.scrollTo(null, grid.columns[0].colDef);
			});
			$timeout.flush();

			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request scroll to column only - last column', function() {
			$timeout(function() {
				grid.scrollTo(null, grid.columns[10].colDef);
			});
			$timeout.flush();

			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request scroll to column only - column 7', function() {
			$timeout(function() {
				grid.scrollTo(null, grid.columns[8].colDef);
			});
			$timeout.flush();

			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request no scroll as no row or column', function() {
			$timeout(function() {
				grid.scrollTo(null, null);
			});
			$timeout.flush();

			expect(args).toEqual(null);
		});
	});
});
<commit_msg>chore: 🤖 update test setup to ensure it runs correctly in build<commit_after>describe('ui.grid.edit uiGridCellNavService', function() {
	var uiGridCellNavService,
		gridClassFactory,
		grid,
		uiGridConstants,
		uiGridCellNavConstants,
		$rootScope,
		$timeout;

	beforeEach(module('ui.grid.cellNav'));

	beforeEach(inject(
		function(_uiGridCellNavService_, _gridClassFactory_, $templateCache, _uiGridConstants_, _uiGridCellNavConstants_, _$rootScope_, _$timeout_) {
			uiGridCellNavService = _uiGridCellNavService_;
			gridClassFactory = _gridClassFactory_;
			uiGridConstants = _uiGridConstants_;
			uiGridCellNavConstants = _uiGridCellNavConstants_;
			$rootScope = _$rootScope_;
			$timeout = _$timeout_;

			$templateCache.put('ui-grid/uiGridCell', '<div/>');

			grid = gridClassFactory.createGrid();
			// throttled scrolling isn't working in tests for some reason
			grid.headerHeight = 10;
			grid.footerHeight = 0;
			grid.gridHeight = 15;
			grid.options.rowHeight = 30;
			grid.options.scrollDebounce = 0;
			grid.options.columnDefs = [
				{name: 'col0', allowCellFocus: true},
				{name: 'col1', allowCellFocus: false},
				{name: 'col2'}
			];

			grid.options.data = [
				{col0: 'row0col0', col1: 'row0col1', col2: 'row0col2'},
				{col0: 'row1col0', col1: 'row1col1', col2: 'row1col2'},
				{col0: 'row2col0', col1: 'row2col1', col2: 'row2col2'}
			];

			uiGridCellNavService.initializeGrid(grid);
			grid.modifyRows(grid.options.data);
		}));

	describe('public Apis function', function() {
		beforeEach(function() {
			grid.buildColumns();
		});

		it('should have getFocusedCell', function() {
			expect(grid.api.cellNav.getFocusedCell()).toBeDefined();
			expect(grid.api.cellNav.getFocusedCell()).toBe(null);
			grid.cellNav.lastRowCol = 'mockRowCol';
			expect(grid.api.cellNav.getFocusedCell()).toBe('mockRowCol');
		});
	});

	describe('cellNavColumnBuilder function', function() {
		beforeEach(function() {
			grid.buildColumns();
		});

		it('should populate allowCellFocus with defaults', function() {
			var colDef = grid.options.columnDefs[0];
			var col = grid.columns[0];
			uiGridCellNavService.cellNavColumnBuilder(colDef, col, grid.options);
			expect(col.colDef.allowCellFocus).toBe(true);

			colDef = grid.options.columnDefs[1];
			col = grid.columns[1];
			uiGridCellNavService.cellNavColumnBuilder(colDef, col, grid.options);
			expect(col.colDef.allowCellFocus).toBe(false);

			colDef = grid.options.columnDefs[2];
			col = grid.columns[2];
			uiGridCellNavService.cellNavColumnBuilder(colDef, col, grid.options);
			expect(col.colDef.allowCellFocus).toBe(true);
		});
	});

	describe('getDirection(evt)', function() {
		beforeEach(function() {
			grid.registerColumnBuilder(uiGridCellNavService.cellNavColumnBuilder);
			grid.buildColumns();
		});
		it('should navigate right on tab', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.TAB;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.RIGHT);
		});

		it('should navigate right on right arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.RIGHT;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.RIGHT);
		});

		it('should navigate left on shift tab', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.TAB;
			evt.shiftKey = true;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.LEFT);
		});

		it('should navigate left on left arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.LEFT;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.LEFT);
		});

		it('should navigate down on enter', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.ENTER;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.DOWN);
		});

		it('should navigate down on down arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.DOWN;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.DOWN);
		});

		it('should navigate up on shift enter', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.ENTER;
			evt.shiftKey = true;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.UP);
		});

		it('should navigate up on up arrow', function() {
			var evt = jQuery.Event('keydown');
			evt.keyCode = uiGridConstants.keymap.UP;
			var direction = uiGridCellNavService.getDirection(evt);
			expect(direction).toBe(uiGridCellNavConstants.direction.UP);
		});

	});

	describe('scrollTo', function() {
		/*
		 * We have 11 rows (10 visible) and 11 columns (10 visible).  The column widths are
		 * 100 for the first 5, and 200 for the second 5.  Column 2 and row 2 are invisible.
		 */
		var args;
		var $scope;

		beforeEach(function() {
			var i, j, row;
			grid.options.columnDefs = [];
			for (i = 0; i < 11; i++) {
				grid.options.columnDefs.push({name: 'col' + i});
			}

			grid.options.data = [];
			for (i = 0; i < 11; i++) {
				row = {};
				for (j = 0; j < 11; j++) {
					row['col' + j] = 'test data ' + i + '_' + j;
				}
				grid.options.data.push(row);
			}

			uiGridCellNavService.initializeGrid(grid);
			grid.modifyRows(grid.options.data);

			grid.registerColumnBuilder(uiGridCellNavService.cellNavColumnBuilder);
			grid.buildColumns();

			grid.columns[2].visible = false;
			grid.rows[2].visible = false;

			grid.setVisibleColumns(grid.columns);
			grid.setVisibleRows(grid.rows);

			grid.renderContainers.body.headerHeight = 0;

			for (i = 0; i < 11; i++) {
				grid.columns[i].drawnWidth = i < 6 ? 100 : 200;
			}

			$scope = $rootScope.$new();

			args = null;
			grid.api.core.on.scrollEnd($scope, function(receivedArgs) {
				args = receivedArgs;
			});
		});

		// these have changed to use scrollToIfNecessary, which is better code
		// but it means these unit tests are now mostly checking that it is the same it used to
		// be, not that it is giving some specified result (i.e. I just updated them to what they were)
		it('should request scroll to row and column', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[4], grid.columns[4].colDef);
			});
			$timeout.flush();

			expect(args.grid).toEqual(grid);
			expect(Math.round(args.y.percentage * 10) / 10).toBe(0.4);
			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request scroll to row only - first row', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[0], null);
			});
			$timeout.flush();

			// TODO: figure out why Safari fails on this check
			if (navigator.userAgent.indexOf('Safari') === -1) {
				expect(args.y.percentage).toBeCloseTo(0.15, 0.01);
			}
		});

		it('should request scroll to row only - last row', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[10], null);
			});
			$timeout.flush();

			expect(args.y.percentage).toBeGreaterThan(0.5);
			expect(args.x).toBe(null);
		});

		it('should request scroll to row only - row 4', function() {
			$timeout(function() {
				grid.scrollTo(grid.options.data[5], null);
			});
			$timeout.flush();

			expect(Math.round(args.y.percentage * 10) / 10).toEqual(0.5);
			expect(args.x).toBe(null);
		});

		it('should request scroll to column only - first column', function() {
			$timeout(function() {
				grid.scrollTo(null, grid.columns[0].colDef);
			});
			$timeout.flush();

			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request scroll to column only - last column', function() {
			$timeout(function() {
				grid.scrollTo(null, grid.columns[10].colDef);
			});
			$timeout.flush();

			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request scroll to column only - column 7', function() {
			$timeout(function() {
				grid.scrollTo(null, grid.columns[8].colDef);
			});
			$timeout.flush();

			expect(isNaN(args.x.percentage)).toEqual(true);
		});

		it('should request no scroll as no row or column', function() {
			$timeout(function() {
				grid.scrollTo(null, null);
			});
			$timeout.flush();

			expect(args).toEqual(null);
		});
	});
});
<|endoftext|>