<commit_before>import stringArgv from 'string-argv';
import { endsWith, trimEnd } from 'lodash/string';
import CommandParserError from '../Errors/CommandParserError';

/**
 * Parses the signature of a command.
 */
export default class Parser {
  /**
   * Some constants for command argument types.
   * @type {Object}
   */
  static TOKEN_TYPES = {
    SINGLE: 'SINGLE',
    ARRAY: 'ARRAY',
  };

  /**
   * Parses a given command signature.
   * @param {String} signature - The command signature.
   * @returns {Object} Object containing data on the command signature.
   */
  static parse(signature) {
    if (!signature.trim()) {
      throw new CommandParserError('Signature cannot not be empty.');
    }

    const partition = signature.split(' ');
    const identifier = partition[0].trim();

    if (partition.length > 1) {
      const matches = partition.slice(1).join(' ').match(/\{\s*(.*?)\s*\}/g);
      const parameters = Parser.parseParameters(matches);

      return {
        identifier,
        parameters,
      };
    }

    return {
      identifier,
    };
  }

  /**
   * Parses the parameters in a command signature.
   * @param {Array<String>} parameters - Array of parameters parsed from the signature.
   * @returns {Array<Object>} Array containing data on the parsed parameters.
   */
  static parseParameters(parameters) {
    const parsed = parameters.reduce(
      (previous, current) => {
        const token = Parser.parseParameter(current);

        if (previous.seen.parameterNames[token.name]) {
          throw new CommandParserError(`Encountered duplicate parameter names: ${token.name}.`);
        } else if (previous.seen.array) {
          throw new CommandParserError(`Argument of type array can only appear at the end of the command signature. Given parameters: <{${parameters.join('} {')}}>.`);
        } else if (!token.optional && previous.seen.optional) {
          throw new CommandParserError(`Encountered required argument after optional argument: ${token.name}.`);
        }

        return {
          seen: {
            array: previous.seen.array || token.type === Parser.TOKEN_TYPES.ARRAY,
            optional: previous.seen.optional || token.optional,
            parameterNames: {
              ...previous.seen.parameterNames,
              [token.name]: true,
            },
          },
          parameters: [...previous.parameters, token],
        };
      },
      {
        seen: {
          array: false,
          optional: false,
          parameterNames: {},
        },
        parameters: [],
      },
    );

    return parsed.parameters;
  }

  /**
   * Parses a single command parameter.
   * @param {String} parameter - The parameter.
   * @returns {Object} Object containing data on the parsed parameter.
   */
  static parseParameter(parameter) {
    const token = {
      name: null,
      description: null,
      type: Parser.TOKEN_TYPES.SINGLE,
      optional: false,
      defaultValue: null,
    };

    let signature;

    if (parameter.indexOf(':') !== -1) {
      [signature, token.description] = parameter.split(':', 2).map(x => x.trim());
    } else {
      signature = parameter;
    }

    const matches = signature.match(/(.+)=(.+)/);

    if (matches) {
      signature = matches[1].trim();
      token.defaultValue = matches[2].trim();
      token.optional = true;
    }

    if (endsWith(signature, '?')) {
      token.optional = true;
      signature = trimEnd(signature, ' ?');
    }

    if (endsWith(signature, '*')) {
      token.type = Parser.TOKEN_TYPES.ARRAY;
      token.defaultValue = token.defaultValue && stringArgv(token.defaultValue).map(x => x.trim());
      signature = trimEnd(signature, ' *');
    }

    token.name = signature;

    return token;
  }
}
<commit_msg>Shorten the code.<commit_after>import stringArgv from 'string-argv';
import { endsWith, trimEnd } from 'lodash/string';
import CommandParserError from '../Errors/CommandParserError';

/**
 * Parses the signature of a command.
 */
export default class Parser {
  /**
   * Some constants for command argument types.
   * @type {Object}
   */
  static TOKEN_TYPES = {
    SINGLE: 'SINGLE',
    ARRAY: 'ARRAY',
  };

  /**
   * Parses a given command signature.
   * @param {String} signature - The command signature.
   * @returns {Object} Object containing data on the command signature.
   */
  static parse(signature) {
    if (!signature.trim()) {
      throw new CommandParserError('Signature cannot not be empty.');
    }

    const partition = signature.split(' ');
    const identifier = partition[0].trim();

    if (partition.length > 1) {
      const matches = partition.slice(1).join(' ').match(/\{\s*(.*?)\s*\}/g);
      const parameters = Parser.parseParameters(matches);

      return {
        identifier,
        parameters,
      };
    }

    return {
      identifier,
    };
  }

  /**
   * Parses the parameters in a command signature.
   * @param {Array<String>} parameters - Array of parameters parsed from the signature.
   * @returns {Array<Object>} Array containing data on the parsed parameters.
   */
  static parseParameters(parameters) {
    return parameters.reduce(
      (previous, current) => {
        const token = Parser.parseParameter(current);

        if (previous.seen.parameterNames[token.name]) {
          throw new CommandParserError(`Encountered duplicate parameter names: ${token.name}.`);
        } else if (previous.seen.array) {
          throw new CommandParserError(`Argument of type array can only appear at the end of the command signature. Given parameters: <{${parameters.join('} {')}}>.`);
        } else if (!token.optional && previous.seen.optional) {
          throw new CommandParserError(`Encountered required argument after optional argument: ${token.name}.`);
        }

        return {
          seen: {
            array: previous.seen.array || token.type === Parser.TOKEN_TYPES.ARRAY,
            optional: previous.seen.optional || token.optional,
            parameterNames: {
              ...previous.seen.parameterNames,
              [token.name]: true,
            },
          },
          parsedParameters: [...previous.parsedParameters, token],
        };
      },
      {
        seen: {
          array: false,
          optional: false,
          parameterNames: {},
        },
        parsedParameters: [],
      },
    ).parsedParameters;
  }

  /**
   * Parses a single command parameter.
   * @param {String} parameter - The parameter.
   * @returns {Object} Object containing data on the parsed parameter.
   */
  static parseParameter(parameter) {
    const token = {
      name: null,
      description: null,
      type: Parser.TOKEN_TYPES.SINGLE,
      optional: false,
      defaultValue: null,
    };

    let signature;

    if (parameter.indexOf(':') !== -1) {
      [signature, token.description] = parameter.split(':', 2).map(x => x.trim());
    } else {
      signature = parameter;
    }

    const matches = signature.match(/(.+)=(.+)/);

    if (matches) {
      signature = matches[1].trim();
      token.defaultValue = matches[2].trim();
      token.optional = true;
    }

    if (endsWith(signature, '?')) {
      token.optional = true;
      signature = trimEnd(signature, ' ?');
    }

    if (endsWith(signature, '*')) {
      token.type = Parser.TOKEN_TYPES.ARRAY;
      token.defaultValue = token.defaultValue && stringArgv(token.defaultValue).map(x => x.trim());
      signature = trimEnd(signature, ' *');
    }

    token.name = signature;

    return token;
  }
}
<|endoftext|>


<commit_before>const assert = require("chai").assert;
const Box = require("@truffle/box");
const TestHelpers = require("@truffle/core/lib/commands/test/helpers");
const Artifactor = require("@truffle/artifactor");
const Resolver = require("@truffle/resolver");
const MemoryStream = require("memorystream");
const path = require("path");
const fs = require("fs-extra");
const glob = require("glob");
const Contracts = require("@truffle/workflow-compile/new");
const Test = require("@truffle/core/lib/test");

let config;
output = "";

function updateFile(filename) {
  const fileToUpdate = path.resolve(
    path.join(config.contracts_directory, filename)
  );

  // Update the modification time to simulate an edit.
  const newTime = new Date().getTime();
  fs.utimesSync(fileToUpdate, newTime, newTime);
}

describe("test command", () => {
  let memStream;

  before("Create a sandbox", async () => {
    config = await Box.sandbox("default");
    config.resolver = new Resolver(config);
    config.artifactor = new Artifactor(config.contracts_build_directory);
    config.networks = {
      default: {
        network_id: "1"
      },
      secondary: {
        network_id: "12345"
      }
    };
    config.network = "default";
    config.logger = { log: val => val && memStream.write(val) };
  });

  beforeEach(() => {
    memStream = new MemoryStream();
    memStream.on("data", data => {
      output += data.toString();
    });
  });

  after("Cleanup tmp files", () => {
    const files = glob.sync("tmp-*");
    files.forEach(file => fs.removeSync(file));
  });

  afterEach("Clear MemoryStream", () => (output = ""));

  it("Check test with subdirectories", () => {
    let testFiles = TestHelpers.determineTestFilesToRun({ config });
    let testFilesCount = testFiles.length;

    let filename = path.join(
      config.test_directory,
      "sub_directory",
      "test.sol"
    );
    fs.createFileSync(filename);

    filename = path.join(config.test_directory, "sub_directory", "test.js");
    fs.createFileSync(filename);

    filename = path.join(
      config.test_directory,
      "sub_directory",
      "sub_sub_directory",
      "test.js"
    );
    fs.createFileSync(filename);

    let dirName = path.join(
      config.test_directory,
      "sub_directory",
      "empty_sub_directory"
    );

    // Create empty subdirectory to check if
    // determineTestFilesTo run function can process it without crashing
    fs.ensureDirSync(dirName);

    let newTestFiles = TestHelpers.determineTestFilesToRun({ config });
    assert.equal(
      newTestFiles.length,
      testFilesCount + 3,
      "Wrong number of files discovered"
    );
  });

  it("runs test with --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: true,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false"
    );
  });

  it("can run test WITHOUT --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      3,
      "It should compile 3 contracts With compileNone == true"
    );
  });

  it("compiles all initial contracts", async () => {
    const { contracts } = await Contracts.compile(
      config.with({
        all: false,
        quiet: true
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      0,
      "Should compile zero contracts. Test command was run before and everything should be up to date"
    );
  });

  it("run test without --compile-none flag after running build", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false. Because there are no updated files."
    );
  });

  it("runs test after updating one contract.", async () => {
    updateFile("ConvertLib.sol");

    const solidityTestFiles = [];

    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      2,
      "It should compile 2 files, updated file and its ancestor,  and --compile-none is not set."
    );
  });

  it("Update all contracts and build it.", async () => {
    updateFile("ConvertLib.sol");
    updateFile("MetaCoin.sol");
    updateFile("Migrations.sol");

    const { contracts } = await Contracts.compile(
      config.with({
        all: false,
        quiet: false
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      3,
      "Should compile 3 contracts."
    );
  });

  it("Check if  files are picked from subdirectories in test directory.", async () => {
    // This allows to create customized directory structure to test more than one level of sub directories.
    let fileStructrure = {
      name: "sub_directory",
      files: ["test1.sol", "test2.js"],
      subdirs: [
        {
          name: "sub_sub_directory",
          files: ["test3.sol", "test4.js"]
        },
        {
          name: "sub_sub_directory2",
          files: ["test5.js", "test6.sol", "test7.sol"],
          subdirs: [
            {
              name: "one_more_sub",
              files: [
                "test8.sol",
                "test9.sol",
                "test10.sol",
                "test10.sol",
                "test11.sol"
              ]
            },
            {
              name: "one_more_sub2",
              files: [
                "test12.sol",
                "test13.sol",
                "test14.sol",
                "test14.sol",
                "test15.sol"
              ],
              subdirs: [
                {
                  name: "solidity_only_subdir",
                  files: ["test16.sol", "test17.sol", "test18.sol"]
                },
                {
                  name: "js_only_subdir",
                  files: ["test19.js", "test19.js", "test20.js"]
                },
                {
                  name: "empty_sub_sub_directory",
                  files: []
                }
              ]
            }
          ]
        }
      ]
    };

    // Create file in recursion. Used instead foreach since foreach loop doesn't wait for files to be created
    // Function does not count already existing files.
    function createFile(dirName, files, index) {
      // return zero if there are no files to create
      if (!files[index]) return 0;
      var fileName = path.join(dirName, files[index]);
      let filesCount = 0;
      if (!fs.existsSync(fileName)) {
        fs.createFileSync(fileName);
        filesCount++;
      }
      if (files.length > index + 1) {
        filesCount += createFile(dirName, files, index + 1);
      }

      return filesCount;
    }

    // Create files using dirStruct object. Count newly created files and skip existing files.
    // Returns number of new files.
    function createTestSubDir(dirName, dirStruct) {
      var numOfFiles = 0;

      numOfFiles = createFile(dirName, dirStruct.files, 0);

      if (dirStruct.subdirs) {
        dirStruct.subdirs.forEach(val => {
          numOfFiles += createTestSubDir(
            path.join(dirName, dirStruct.name, val.name),
            val
          );
        });
      }
      return numOfFiles;
    }

    // Call method used by Test to discover existing test files. Then create subdirectories and test files in these
    // subdirectories. Then run Test method again and check if number discovered increased.
    let testFiles = TestHelpers.determineTestFilesToRun({ config });
    const testFilesCount = testFiles.length;

    const newTestFiles = createTestSubDir(
      config.test_directory,
      fileStructrure
    );

    testFiles = TestHelpers.determineTestFilesToRun({ config });
    assert.equal(
      testFiles.length,
      testFilesCount + newTestFiles,
      "Wrong number of files discovered"
    );
  });
}).timeout(1000);
<commit_msg>Update import<commit_after>const assert = require("chai").assert;
const Box = require("@truffle/box");
const TestHelpers = require("@truffle/core/lib/commands/test/helpers");
const Artifactor = require("@truffle/artifactor");
const Resolver = require("@truffle/resolver");
const MemoryStream = require("memorystream");
const path = require("path");
const fs = require("fs-extra");
const glob = require("glob");
const WorkflowCompile = require("@truffle/workflow-compile");
const Test = require("@truffle/core/lib/test");

let config;
output = "";

function updateFile(filename) {
  const fileToUpdate = path.resolve(
    path.join(config.contracts_directory, filename)
  );

  // Update the modification time to simulate an edit.
  const newTime = new Date().getTime();
  fs.utimesSync(fileToUpdate, newTime, newTime);
}

describe("test command", () => {
  let memStream;

  before("Create a sandbox", async () => {
    config = await Box.sandbox("default");
    config.resolver = new Resolver(config);
    config.artifactor = new Artifactor(config.contracts_build_directory);
    config.networks = {
      default: {
        network_id: "1"
      },
      secondary: {
        network_id: "12345"
      }
    };
    config.network = "default";
    config.logger = { log: val => val && memStream.write(val) };
  });

  beforeEach(() => {
    memStream = new MemoryStream();
    memStream.on("data", data => {
      output += data.toString();
    });
  });

  after("Cleanup tmp files", () => {
    const files = glob.sync("tmp-*");
    files.forEach(file => fs.removeSync(file));
  });

  afterEach("Clear MemoryStream", () => (output = ""));

  it("Check test with subdirectories", () => {
    let testFiles = TestHelpers.determineTestFilesToRun({ config });
    let testFilesCount = testFiles.length;

    let filename = path.join(
      config.test_directory,
      "sub_directory",
      "test.sol"
    );
    fs.createFileSync(filename);

    filename = path.join(config.test_directory, "sub_directory", "test.js");
    fs.createFileSync(filename);

    filename = path.join(
      config.test_directory,
      "sub_directory",
      "sub_sub_directory",
      "test.js"
    );
    fs.createFileSync(filename);

    let dirName = path.join(
      config.test_directory,
      "sub_directory",
      "empty_sub_directory"
    );

    // Create empty subdirectory to check if
    // determineTestFilesTo run function can process it without crashing
    fs.ensureDirSync(dirName);

    let newTestFiles = TestHelpers.determineTestFilesToRun({ config });
    assert.equal(
      newTestFiles.length,
      testFilesCount + 3,
      "Wrong number of files discovered"
    );
  });

  it("runs test with --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: true,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false"
    );
  });

  it("can run test WITHOUT --compile-none flag", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      3,
      "It should compile 3 contracts With compileNone == true"
    );
  });

  it("compiles all initial contracts", async () => {
    const { contracts } = await WorkflowCompile.compile(
      config.with({
        all: false,
        quiet: true
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      0,
      "Should compile zero contracts. Test command was run before and everything should be up to date"
    );
  });

  it("run test without --compile-none flag after running build", async () => {
    const solidityTestFiles = [];
    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      0,
      "It should try to compile 0 contracts With compileNone == false. Because there are no updated files."
    );
  });

  it("runs test after updating one contract.", async () => {
    updateFile("ConvertLib.sol");

    const solidityTestFiles = [];

    const { contracts } = await Test.compileContractsWithTestFilesIfNeeded(
      solidityTestFiles,
      config.with({
        all: false,
        compileNone: false,
        quiet: false,
        test_files: solidityTestFiles
      }),
      config.resolver
    );
    assert.equal(
      contracts.length,
      2,
      "It should compile 2 files, updated file and its ancestor,  and --compile-none is not set."
    );
  });

  it("Update all contracts and build it.", async () => {
    updateFile("ConvertLib.sol");
    updateFile("MetaCoin.sol");
    updateFile("Migrations.sol");

    const { contracts } = await WorkflowCompile.compile(
      config.with({
        all: false,
        quiet: false
      })
    );
    assert.equal(
      Object.keys(contracts).length,
      3,
      "Should compile 3 contracts."
    );
  });

  it("Check if  files are picked from subdirectories in test directory.", async () => {
    // This allows to create customized directory structure to test more than one level of sub directories.
    let fileStructrure = {
      name: "sub_directory",
      files: ["test1.sol", "test2.js"],
      subdirs: [
        {
          name: "sub_sub_directory",
          files: ["test3.sol", "test4.js"]
        },
        {
          name: "sub_sub_directory2",
          files: ["test5.js", "test6.sol", "test7.sol"],
          subdirs: [
            {
              name: "one_more_sub",
              files: [
                "test8.sol",
                "test9.sol",
                "test10.sol",
                "test10.sol",
                "test11.sol"
              ]
            },
            {
              name: "one_more_sub2",
              files: [
                "test12.sol",
                "test13.sol",
                "test14.sol",
                "test14.sol",
                "test15.sol"
              ],
              subdirs: [
                {
                  name: "solidity_only_subdir",
                  files: ["test16.sol", "test17.sol", "test18.sol"]
                },
                {
                  name: "js_only_subdir",
                  files: ["test19.js", "test19.js", "test20.js"]
                },
                {
                  name: "empty_sub_sub_directory",
                  files: []
                }
              ]
            }
          ]
        }
      ]
    };

    // Create file in recursion. Used instead foreach since foreach loop doesn't wait for files to be created
    // Function does not count already existing files.
    function createFile(dirName, files, index) {
      // return zero if there are no files to create
      if (!files[index]) return 0;
      var fileName = path.join(dirName, files[index]);
      let filesCount = 0;
      if (!fs.existsSync(fileName)) {
        fs.createFileSync(fileName);
        filesCount++;
      }
      if (files.length > index + 1) {
        filesCount += createFile(dirName, files, index + 1);
      }

      return filesCount;
    }

    // Create files using dirStruct object. Count newly created files and skip existing files.
    // Returns number of new files.
    function createTestSubDir(dirName, dirStruct) {
      var numOfFiles = 0;

      numOfFiles = createFile(dirName, dirStruct.files, 0);

      if (dirStruct.subdirs) {
        dirStruct.subdirs.forEach(val => {
          numOfFiles += createTestSubDir(
            path.join(dirName, dirStruct.name, val.name),
            val
          );
        });
      }
      return numOfFiles;
    }

    // Call method used by Test to discover existing test files. Then create subdirectories and test files in these
    // subdirectories. Then run Test method again and check if number discovered increased.
    let testFiles = TestHelpers.determineTestFilesToRun({ config });
    const testFilesCount = testFiles.length;

    const newTestFiles = createTestSubDir(
      config.test_directory,
      fileStructrure
    );

    testFiles = TestHelpers.determineTestFilesToRun({ config });
    assert.equal(
      testFiles.length,
      testFilesCount + newTestFiles,
      "Wrong number of files discovered"
    );
  });
}).timeout(1000);
<|endoftext|>


<commit_before>import React from 'react';
import SprkSelectionInput from './SprkSelectionInput/SprkSelectionInput';
import SprkSelect from './SprkSelect/SprkSelect';
import SprkIcon from '../../components/icons/SprkIcon';
import SprkInputContainer from './SprkInputContainer/SprkInputContainer';
import SprkFieldError from './SprkFieldError/SprkFieldError';
import { markdownDocumentationLinkBuilder } from '../../../../storybook-utilities/markdownDocumentationLinkBuilder';
import SprkLabel from './SprkLabel/SprkLabel';

export default {
  title: 'Components/Input/Select',
  decorators: [(story) =>
{story()}
],
  component: SprkSelect,
  parameters: {
    jest: [
      'SprkSelect',
      'SprkErrorContainer',
      'SprkInputIconCheck',
      'SprkIcon',
      'SprkLabel',
    ],
    info: `${markdownDocumentationLinkBuilder('input')}`,
  },
};

export const selectBox = () => (
  <SprkInputContainer>
    <SprkLabel htmlFor="default-select">Select Box Label</SprkLabel>
    <SprkSelect
      id="default-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      name="select"
    />
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

selectBox.story = {
  name: 'Default',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const invalidSelectBox = () => (
  <SprkInputContainer>
    <SprkLabel htmlFor="invalid-select">Select Box Label</SprkLabel>
    <SprkSelect
      id="invalid-select"
      ariaDescribedBy="select-invalid-error"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      name="select"
      isValid={false}
    />
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
              sprk-c-Icon--filled-current-color
              sprk-c-Icon--stroke-current-color
              sprk-b-SelectContainer__icon"
    />
    <SprkFieldError id="select-invalid-error">
      <SprkIcon
        iconName="exclamation-filled"
        additionalClasses="sprk-b-ErrorIcon"
        aria-hidden="true"
      />

There is an error on this field.

    </SprkFieldError>
  </SprkInputContainer>
);

invalidSelectBox.story = {
  name: 'Invalid',
  parameters: {
    jest: ['SprkInputContainer', 'SprkFieldError', 'SprkIcon'],
  },
};

export const disabledSelectBox = () => (
  <SprkInputContainer>
    <SprkLabel isDisabled htmlFor="disabled-select">
      Select Box Label
    </SprkLabel>
    <SprkSelect
      id="disabled-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      name="disabled-select"
      isDisabled
    />
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

disabledSelectBox.story = {
  name: 'Disabled',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const hugeSelectBox = () => (
  <SprkInputContainer variant="huge">
    <SprkSelect
      id="huge-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      variant="huge"
      name="select"
      defaultValue=""
    />
    <SprkLabel htmlFor="huge-select">Select Box Label</SprkLabel>
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

hugeSelectBox.story = {
  name: 'Huge',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const invalidHugeSelectBox = () => (
  <SprkInputContainer variant="huge">
    <SprkSelect
      id="select-huge-invalid"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      variant="huge"
      name="select-huge-invalid"
      ariaDescribedBy="select-huge-invalid"
      isValid={false}
      defaultValue=""
    />
    <SprkLabel htmlFor="select-huge-invalid">Select Box Label</SprkLabel>
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
    <SprkFieldError id="select-huge-invalid">
      <SprkIcon
        aria-hidden="true"
        iconName="exclamation-filled"
        additionalClasses="sprk-b-ErrorIcon"
      />

There is an error on this field.

    </SprkFieldError>
  </SprkInputContainer>
);

invalidHugeSelectBox.story = {
  name: 'Huge Invalid',
  parameters: {
    jest: ['SprkInputContainer', 'SprkFieldError', 'SprkIcon'],
  },
};

export const disabledHugeSelectBox = () => (
  <SprkInputContainer variant="huge">
    <SprkSelect
      id="huge-disabled-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      variant="huge"
      name="huge-disabled-select"
      isDisabled
      defaultValue=""
    />
    <SprkLabel htmlFor="huge-disabled-select" isDisabled>
      Select Box Label
    </SprkLabel>
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

disabledHugeSelectBox.story = {
  name: 'Huge Disabled',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const legacySelectBox = () => (
  <SprkSelectionInput
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    name="name"
    variant="select"
    label="Select Box Label"
  />
);

legacySelectBox.story = {
  name: 'Legacy (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyInvalidSelectBox = () => (
  <SprkSelectionInput
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    name="name"
    variant="select"
    label="Select Box Label"
    valid={false}
    errorMessage="There is an error on this field."
  />
);

legacyInvalidSelectBox.story = {
  name: 'Legacy Invalid (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyDisabledSelectBox = () => (
  <SprkSelectionInput
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    name="name"
    variant="select"
    label="Select Box Label"
    disabled
  />
);

legacyDisabledSelectBox.story = {
  name: 'Legacy Disabled (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyHugeSelectBox = () => (
  <SprkSelectionInput
    label="Select Box Label"
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    variant="hugeSelect"
    name="select"
    defaultValue=""
  />
);

legacyHugeSelectBox.story = {
  name: 'Legacy Huge (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyInvalidHugeSelectBox = () => (
  <SprkSelectionInput
    label="Select Box Label"
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    variant="hugeSelect"
    name="select"
    valid={false}
    errorMessage="There is an error in the field."
    defaultValue=""
  />
);

legacyInvalidHugeSelectBox.story = {
  name: 'Legacy Huge Invalid (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyDisabledHugeSelectBox = () => (
  <SprkSelectionInput
    label="Select Box Label"
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    variant="hugeSelect"
    name="select"
    disabled
    defaultValue=""
  />
);

legacyDisabledHugeSelectBox.story = {
  name: 'Legacy Huge Disabled (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};
<commit_msg>spacing<commit_after>import React from 'react';
import SprkSelectionInput from './SprkSelectionInput/SprkSelectionInput';
import SprkSelect from './SprkSelect/SprkSelect';
import SprkIcon from '../../components/icons/SprkIcon';
import SprkInputContainer from './SprkInputContainer/SprkInputContainer';
import SprkFieldError from './SprkFieldError/SprkFieldError';
import { markdownDocumentationLinkBuilder } from '../../../../storybook-utilities/markdownDocumentationLinkBuilder';
import SprkLabel from './SprkLabel/SprkLabel';

export default {
  title: 'Components/Input/Select',
  decorators: [(story) =>
{story()}
],
  component: SprkSelect,
  parameters: {
    jest: [
      'SprkSelect',
      'SprkErrorContainer',
      'SprkInputIconCheck',
      'SprkIcon',
      'SprkLabel',
    ],
    info: `${markdownDocumentationLinkBuilder('input')}`,
  },
};

export const selectBox = () => (
  <SprkInputContainer>
    <SprkLabel htmlFor="default-select">Select Box Label</SprkLabel>
    <SprkSelect
      id="default-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      name="select"
    />
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

selectBox.story = {
  name: 'Default',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const invalidSelectBox = () => (
  <SprkInputContainer>
    <SprkLabel htmlFor="invalid-select">Select Box Label</SprkLabel>
    <SprkSelect
      id="invalid-select"
      ariaDescribedBy="select-invalid-error"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      name="select"
      isValid={false}
    />
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
    <SprkFieldError id="select-invalid-error">
      <SprkIcon
        iconName="exclamation-filled"
        additionalClasses="sprk-b-ErrorIcon"
        aria-hidden="true"
      />

There is an error on this field.

    </SprkFieldError>
  </SprkInputContainer>
);

invalidSelectBox.story = {
  name: 'Invalid',
  parameters: {
    jest: ['SprkInputContainer', 'SprkFieldError', 'SprkIcon'],
  },
};

export const disabledSelectBox = () => (
  <SprkInputContainer>
    <SprkLabel isDisabled htmlFor="disabled-select">
      Select Box Label
    </SprkLabel>
    <SprkSelect
      id="disabled-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      name="disabled-select"
      isDisabled
    />
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

disabledSelectBox.story = {
  name: 'Disabled',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const hugeSelectBox = () => (
  <SprkInputContainer variant="huge">
    <SprkSelect
      id="huge-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      variant="huge"
      name="select"
      defaultValue=""
    />
    <SprkLabel htmlFor="huge-select">Select Box Label</SprkLabel>
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

hugeSelectBox.story = {
  name: 'Huge',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const invalidHugeSelectBox = () => (
  <SprkInputContainer variant="huge">
    <SprkSelect
      id="select-huge-invalid"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      variant="huge"
      name="select-huge-invalid"
      ariaDescribedBy="select-huge-invalid"
      isValid={false}
      defaultValue=""
    />
    <SprkLabel htmlFor="select-huge-invalid">Select Box Label</SprkLabel>
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
    <SprkFieldError id="select-huge-invalid">
      <SprkIcon
        aria-hidden="true"
        iconName="exclamation-filled"
        additionalClasses="sprk-b-ErrorIcon"
      />

There is an error on this field.

    </SprkFieldError>
  </SprkInputContainer>
);

invalidHugeSelectBox.story = {
  name: 'Huge Invalid',
  parameters: {
    jest: ['SprkInputContainer', 'SprkFieldError', 'SprkIcon'],
  },
};

export const disabledHugeSelectBox = () => (
  <SprkInputContainer variant="huge">
    <SprkSelect
      id="huge-disabled-select"
      choices={[
        {
          label: 'Option 1',
          value: 'option-1',
        },
        {
          label: 'Option 2',
          value: 'option-2',
        },
        {
          label: 'Option 3',
          value: 'option-3',
        },
        {
          label: 'Grouped Options',
          options: [
            {
              label: 'Grouped Option 1',
              value: 'grouped-option-1',
            },
            {
              label: 'Grouped Option 2',
              value: 'grouped-option-2',
            },
            {
              label: 'Grouped Option 3',
              value: 'grouped-option-3',
            },
          ],
        },
      ]}
      variant="huge"
      name="huge-disabled-select"
      isDisabled
      defaultValue=""
    />
    <SprkLabel htmlFor="huge-disabled-select" isDisabled>
      Select Box Label
    </SprkLabel>
    <SprkIcon
      iconName="chevron-down"
      aria-hidden="true"
      additionalClasses="
        sprk-c-Icon--filled-current-color
        sprk-c-Icon--stroke-current-color
        sprk-b-SelectContainer__icon
      "
    />
  </SprkInputContainer>
);

disabledHugeSelectBox.story = {
  name: 'Huge Disabled',
  parameters: {
    jest: ['SprkInputContainer'],
  },
};

export const legacySelectBox = () => (
  <SprkSelectionInput
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    name="name"
    variant="select"
    label="Select Box Label"
  />
);

legacySelectBox.story = {
  name: 'Legacy (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyInvalidSelectBox = () => (
  <SprkSelectionInput
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    name="name"
    variant="select"
    label="Select Box Label"
    valid={false}
    errorMessage="There is an error on this field."
  />
);

legacyInvalidSelectBox.story = {
  name: 'Legacy Invalid (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyDisabledSelectBox = () => (
  <SprkSelectionInput
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    name="name"
    variant="select"
    label="Select Box Label"
    disabled
  />
);

legacyDisabledSelectBox.story = {
  name: 'Legacy Disabled (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyHugeSelectBox = () => (
  <SprkSelectionInput
    label="Select Box Label"
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    variant="hugeSelect"
    name="select"
    defaultValue=""
  />
);

legacyHugeSelectBox.story = {
  name: 'Legacy Huge (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyInvalidHugeSelectBox = () => (
  <SprkSelectionInput
    label="Select Box Label"
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    variant="hugeSelect"
    name="select"
    valid={false}
    errorMessage="There is an error in the field."
    defaultValue=""
  />
);

legacyInvalidHugeSelectBox.story = {
  name: 'Legacy Huge Invalid (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};

export const legacyDisabledHugeSelectBox = () => (
  <SprkSelectionInput
    label="Select Box Label"
    choices={[
      {
        label: 'Option 1',
        value: 'option-1',
      },
      {
        label: 'Option 2',
        value: 'option-2',
      },
      {
        label: 'Option 3',
        value: 'option-3',
      },
      {
        label: 'Grouped Options',
        options: [
          {
            label: 'Grouped Option 1',
            value: 'grouped-option-1',
          },
          {
            label: 'Grouped Option 2',
            value: 'grouped-option-2',
          },
          {
            label: 'Grouped Option 3',
            value: 'grouped-option-3',
          },
        ],
      },
    ]}
    variant="hugeSelect"
    name="select"
    disabled
    defaultValue=""
  />
);

legacyDisabledHugeSelectBox.story = {
  name: 'Legacy Huge Disabled (Deprecated)',
  parameters: {
    jest: ['SprkSelectionInput'],
  },
};
<|endoftext|>


<commit_before>import React from 'react';
import Link from 'components/link';
import { MenuListItem, MenuList } from 'components/menu-list';
import { humanize, titleize } from 'underscore.string';
import { startsWith } from 'lodash';
import SiteMap from '../../../site-map';
import './generate-menu.scss';

const humanName = (key) => {
  return titleize(humanize(key.replace('/', '')));
};

const createMenuLink = (name, url, active, external, isMainLink) => {
  const classes = [];

  if (active) classes.push('demo-menu__link--active');
  if (isMainLink) classes.push('demo-menu__link');

  const linkProp = external ? { href: url, target: '_blank' } : { to: url };

  return (
    <MenuListItem key={ name } name={ humanName(name) }>
      <Link className={ classes } { ...linkProp }>
        { humanName(name) }
      </Link>
    </MenuListItem>
  );
};

const createSubmenu = (url, value) => {
  const submenuItems = [];
  let initiallyOpen = false;

  for (const index in value.items) {
    let name, link = value.items[index], external = false;

    if (typeof link === 'string' && startsWith(link, 'http')) {
      name = index;
      external = true;
    } else if (url.indexOf(':name') > -1) {
      name = value.items[index];
      link = url.replace(':name', name);
    } else {
      name = index;
      link = `${url}/${name}`;
    }

    const active = (window.location.pathname === link);
    submenuItems.push(createMenuLink(name, link, active, external));
  }

  let title = url.replace(/\//g, '');
  title = titleize(humanize(title.replace(':name', '')));

  if (url.split('/')[1] === window.location.pathname.split('/')[1]) {
    initiallyOpen = true;
  }

  return (
    <MenuListItem key={ title }>
      <MenuList
        title={ title }
        initiallyOpen={ initiallyOpen }
        filter={ value.filter }
        filterPlaceholder='Filter Components'
      >
        { submenuItems }
      </MenuList>
    </MenuListItem>
  );
};

const generateMenu = () => {
  const menu = [];

  for (const key in SiteMap.config) {
    const url = key,
        value = SiteMap.config[key],
        menuItems = [];

    if (value.items) {
      menuItems.push(createSubmenu(url, value));
    } else if (value.component) {
      menuItems.push(createMenuLink(url, url));
    }

    menu.push(menuItems);
  }

  menu.push(createMenuLink('Component Library', '/storybook', false, false, true));

  return menu;
};

export default () => {
  return generateMenu();
};
<commit_msg>Ensure storybook link is followed<commit_after>import React from 'react';
import Link from 'components/link';
import { MenuListItem, MenuList } from 'components/menu-list';
import { humanize, titleize } from 'underscore.string';
import { startsWith } from 'lodash';
import SiteMap from '../../../site-map';
import './generate-menu.scss';

const humanName = (key) => {
  return titleize(humanize(key.replace('/', '')));
};

const createMenuLink = (name, url, active, external, isMainLink) => {
  const classes = [];

  if (active) classes.push('demo-menu__link--active');
  if (isMainLink) classes.push('demo-menu__link');

  const linkProp = external ? { href: url, target: '_blank' } : { to: url };

  return (
    <MenuListItem key={ name } name={ humanName(name) }>
      <Link className={ classes } { ...linkProp }>
        { humanName(name) }
      </Link>
    </MenuListItem>
  );
};

const createSubmenu = (url, value) => {
  const submenuItems = [];
  let initiallyOpen = false;

  for (const index in value.items) {
    let name, link = value.items[index], external = false;

    if (typeof link === 'string' && startsWith(link, 'http')) {
      name = index;
      external = true;
    } else if (url.indexOf(':name') > -1) {
      name = value.items[index];
      link = url.replace(':name', name);
    } else {
      name = index;
      link = `${url}/${name}`;
    }

    const active = (window.location.pathname === link);
    submenuItems.push(createMenuLink(name, link, active, external));
  }

  let title = url.replace(/\//g, '');
  title = titleize(humanize(title.replace(':name', '')));

  if (url.split('/')[1] === window.location.pathname.split('/')[1]) {
    initiallyOpen = true;
  }

  return (
    <MenuListItem key={ title }>
      <MenuList
        title={ title }
        initiallyOpen={ initiallyOpen }
        filter={ value.filter }
        filterPlaceholder='Filter Components'
      >
        { submenuItems }
      </MenuList>
    </MenuListItem>
  );
};

const generateMenu = () => {
  const menu = [];

  for (const key in SiteMap.config) {
    const url = key,
        value = SiteMap.config[key],
        menuItems = [];

    if (value.items) {
      menuItems.push(createSubmenu(url, value));
    } else if (value.component) {
      menuItems.push(createMenuLink(url, url));
    }

    menu.push(menuItems);
  }

  menu.push(createStorybookLink());

  return menu;
};

const createStorybookLink = () => {
  const classes = ['demo-menu__link'];
  const linkProp = { href: '/storybook' };
  const name = 'Component Library';

  return (
    <MenuListItem key={ name } name={ humanName(name) }>
      <Link className={ classes } { ...linkProp }>
        { humanName(name) }
      </Link>
    </MenuListItem>
  );
};

export default () => {
  return generateMenu();
};
<|endoftext|>


<commit_before>/* global ace removeAllVCMarkers */

var createEditor;
var author;

function injectCreate(id) {
    $("#" + id).load("right/html/rightHTML", function () {
        injectCreateEditor();

        // Check to see if we already have an author ID
        if (localStorage.getItem("author")) {
            // Reuse the same author ID
            author = localStorage.getItem("author");
        } else {
            // Generate a random number from 1 to 10000
            author = Math.floor(Math.random() * 10000 + 1);
            localStorage.setItem("author", author);
        }
    });
}

function injectCreateEditor() {
    var ResolveMode = ace.require("ace/mode/resolve").Mode;

    Range = ace.require("ace/range").Range;
    createEditor = ace.edit("editor");
    createEditor.setTheme("ace/theme/github");

    // Set this to RESOLVE mode
    createEditor.session.setMode(new ResolveMode());

    // Gets rid of a weird Ace Editor bug
    // createEditor.$blockScrolling = Infinity;

    createEditor.getSession().on("change", removeAllVCMarkers);
    createEditor.setFontSize(18);
}
<commit_msg>Intermediate commite<commit_after>/* global ace removeAllVCMarkers */

var createEditor;
var author;

function injectCreate(id) {
    $("#" + id).load("right/html/rightHTML", function () {
        injectCreateEditor();

        // Check to see if we already have an author ID
        if (localStorage.getItem("author")) {
            // Reuse the same author ID
            author = localStorage.getItem("author");
        } else {
            // Generate a random number from 1 to 10000
            author = Math.floor(Math.random() * 10000 + 1);
            localStorage.setItem("author", author);
        }
    });
}

function injectCreateEditor() {
    var ResolveMode = ace.require("ace/mode/resolve").Mode;

    Range = ace.require("ace/range").Range;
    createEditor = ace.edit("editor");
    createEditor.setTheme("ace/theme/github");

    // Set this to RESOLVE mode
    createEditor.session.setMode(new ResolveMode());

    // Gets rid of a weird Ace Editor bug
    // createEditor.$blockScrolling = Infinity;

    createEditor.setFontSize(18);
    createEditor.on("change", removeAllVCMarkers);
    createEditor.on("change", checkEdit);
}

function checkEdit(change) {
    var arr = [change];
    arr.forEach(function(obj){console.log(obj);});
    createEditor.getSession().undoChanges(arr, true);
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, Compiler Explorer Authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
"use strict";

const
    fs = require('fs-extra'),
    path = require('path'),
    utils = require('../utils'),
    _ = require('underscore'),
    BaseTool = require('./base-tool');

class CompilerDropinTool extends BaseTool {
    constructor(toolInfo, env) {
        super(toolInfo, env);
    }

    // mostly copy&paste from base-compiler.js
    // FIXME: remove once #1617 is merged
    findLibVersion(selectedLib, compiler) {
        const foundLib = _.find(compiler.libs, (o, libId) => libId === selectedLib.id);
        if (!foundLib) return false;

        const foundVersion = _.find(foundLib.versions, (o, versionId) => versionId === selectedLib.version);
        return foundVersion;
    }

    // mostly copy&paste from base-compiler.js
    getIncludeArguments(libraries, compiler) {
        const includeFlag = "-I";

        return _.flatten(_.map(libraries, (selectedLib) => {
            const foundVersion = this.findLibVersion(selectedLib, compiler);
            if (!foundVersion) return false;

            return _.map(foundVersion.path, (path) => includeFlag + path);
        }));
    }

    runTool(compilationInfo, inputFilepath, args, stdin) {
        const sourcefile = inputFilepath;
        const compilerExe = compilationInfo.compiler.exe;
        const options = compilationInfo.options;
        const dir = path.dirname(sourcefile);

        const includeflags = this.getIncludeArguments(compilationInfo.libraries, compilationInfo.compiler);

        // order should be:
        //  1) options from the compiler config (compilationInfo.compiler.options)
        //  2) includes from the libraries (includeflags)
        //  3) options from the tool config (this.tool.options)
        //  4) options manually specified in the compiler tab (options)
        //  5) flags from the clang-tidy tab
        let compileFlags = compilationInfo.compiler.options.split(" ");
        compileFlags = compileFlags.concat(includeflags);

        const manualCompileFlags = options.filter(option => (option !== sourcefile));
        compileFlags = compileFlags.concat(manualCompileFlags);
        compileFlags = compileFlags.concat(this.tool.options.split(" "));
        compileFlags = compileFlags.concat(args);

        return super.runTool(compilationInfo, sourcefile, compileFlags);
    }
}

module.exports = CompilerDropinTool;
<commit_msg>fixes<commit_after>// Copyright (c) 2019, Compiler Explorer Authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
"use strict";

const
    _ = require('underscore'),
    BaseTool = require('./base-tool');

class CompilerDropinTool extends BaseTool {
    constructor(toolInfo, env) {
        super(toolInfo, env);
    }

    // mostly copy&paste from base-compiler.js
    // FIXME: remove once #1617 is merged
    findLibVersion(selectedLib, compiler) {
        const foundLib = _.find(compiler.libs, (o, libId) => libId === selectedLib.id);
        if (!foundLib) return false;

        const foundVersion = _.find(foundLib.versions, (o, versionId) => versionId === selectedLib.version);
        return foundVersion;
    }

    // mostly copy&paste from base-compiler.js
    getIncludeArguments(libraries, compiler) {
        const includeFlag = "-I";

        return _.flatten(_.map(libraries, (selectedLib) => {
            const foundVersion = this.findLibVersion(selectedLib, compiler);
            if (!foundVersion) return false;

            return _.map(foundVersion.path, (path) => includeFlag + path);
        }));
    }

    runTool(compilationInfo, inputFilepath, args) {
        const sourcefile = inputFilepath;
        const options = compilationInfo.options;

        const includeflags = this.getIncludeArguments(compilationInfo.libraries, compilationInfo.compiler);

        // order should be:
        //  1) options from the compiler config (compilationInfo.compiler.options)
        //  2) includes from the libraries (includeflags)
        //  3) options from the tool config (this.tool.options)
        //  4) options manually specified in the compiler tab (options)
        //  5) flags from the clang-tidy tab
        const compilerOptions = compilationInfo.compiler.options ? compilationInfo.compiler.options.split(" ") : [];
        let compileFlags = compilerOptions;
        compileFlags = compileFlags.concat(includeflags);

        const manualCompileFlags = options.filter(option => (option !== sourcefile));
        compileFlags = compileFlags.concat(manualCompileFlags);
        const toolOptions = this.tool.options ? this.tool.options.split(" ") : [];
        compileFlags = compileFlags.concat(toolOptions);
        args ? args : [];
        compileFlags = compileFlags.concat(args);

        return super.runTool(compilationInfo, sourcefile, compileFlags);
    }
}

module.exports = CompilerDropinTool;
<|endoftext|>


<commit_before>const gulp = require('gulp'),
    gutil = require('gulp-util'),
    fs = require('fs'),
    jade = require('gulp-jade'),
    browserSync = require('browser-sync');

const pages = ["about", "committees", "contact", "place", "sponsors", "timeline",
              "theme"];
/* processTemplate(path_name_of_template, options_of_file_types)
 * Take Everything inside the template folder,
 * process everything (jade, uglify, minify, etc),
 * and output it into the public/template folder
 * If the template is 'home', put in public_root
*/
function processTemplate(file, ops) {
  gutil.log('Going To Process content in ' + file);

  var end = 'public/' + file;
  var start = 'templates/' + file;

  if(file == 'home') {
    end = 'public';
  }

  if(ops.jade || ops.all) {
    gutil.log('--Doing Jade...');
    gulp.src(start+"/*.jade")
      .pipe(jade({pretty: true}))
      //TODO Inject uglify and minify
      .pipe(gulp.dest(end));
    gutil.log('--Finished Jade');
  }
  if(ops.rest || ops.all) {
    gutil.log('--Doing Rest...');
    gulp.src([start+'/*.*', '!'+start+'/*.html', '!'+start+'/*.jade'])
    //TODO Inject uglify and minify
      .pipe(gulp.dest(end));
    gutil.log('--Finished Rest');
  }
}

function compile(ops) {

  var doJade = ops.jade || ops.all || false;
  var doRest = ops.rest || ops.all || false;
  var doCss  = ops.css  || ops.all || false;

  fs.readdir(__dirname+'/templates', function(err, files) {
    if(err)
      return gutil.log('Error while reading files from: ' + __dirname);
    // Read Each File that starts with '_'
    files
      //file.startsWith('_')
      .filter((file) => ['template.jade'].indexOf(file) === -1 )
      .forEach((file) => {
        gutil.log('File to be Processed: ' + file);
        processTemplate(file, ops);
      });
      gutil.log('Finished Compiling Templates!');
  });
}

function transfer() {
  gutil.log('Transfering Assets...');
  gulp.src('assets/**/*.*')
    .pipe(gulp.dest('public/assets'));
}

gulp.task('jade', function() {
  compile({jade: true});
});

gulp.task('css', function() {
  compile({css: true})
});

gulp.task('build', function() {
  compile({all: true});

});

gulp.task('release', function() {
  compile({all: true});
  transfer();
});

gulp.task('browserSync', function() {
    browserSync.init({
      server: {
        baseDir: './public'
      }
    });
    gulp.watch('public/**/*.*', browserSync.reload);
    //gulp.watch(['./**/*.css', './**/*.jade', '!public'], ['build'])
    // Everything that is a jade file should be rebuilt
    gulp.watch(['templates/**/*.jade'], ['jade']);
    // Everything that is note a jade file should be passed
    gulp.watch(['templates/**/*.*', '!templates/**/*.jade', '!templates/**/*.html'], function(event) {
      // Get Name Of the Template Page
      var rel = event.path.substring(__dirname.length+'/templates/'.length);
      rel = rel.split('/')[0];
      gutil.log(rel);
      processTemplate(rel, {rest: true});
    });
});

gulp.task('run', ['build', 'browserSync']);

gulp.task('clean', function() {
  gutil.log('Cleaning...');
  // Remove everything in Public/
  // Remove every .html from templates
});

gulp.task('default', ['build']);
<commit_msg>Restructuing gulp<commit_after>const gulp = require('gulp'),
    gutil = require('gulp-util'),
    fs = require('fs'),
    jade = require('gulp-jade'),
    browserSync = require('browser-sync');

/*
  - Jade Templates en templates/...
  - Css En Templates/...
  - Tenemos Css en assets/styles/...
  - Process Css en css pipeline
  - Assets/js-customelements
*/

const pages = ["about", "committees", "contact", "place", "sponsors", "timeline",
              "theme"];

const routes = {
  templates: [__dirname + '']
  assets: [__dirname + ''],
  release: ['']
}
/* processTemplate(path_name_of_template, options_of_file_types)
 * Take Everything inside the template folder,
 * process everything (jade, uglify, minify, etc),
 * and output it into the public/template folder
 * If the template is 'home', put in public_root
*/
function processTemplate(file, ops) {
  gutil.log('Going To Process content in ' + file);

  var end = 'public/' + file;
  var start = 'templates/' + file;

  if(file == 'home') {
    end = 'public';
  }

  if(ops.jade || ops.all) {
    gutil.log('--Doing Jade...');
    gulp.src(start+"/*.jade")
      .pipe(jade({pretty: true}))
      //TODO Inject uglify and minify
      .pipe(gulp.dest(end));
    gutil.log('--Finished Jade');
  }
  if(ops.rest || ops.all) {
    gutil.log('--Doing Rest...');
    gulp.src([start+'/*.*', '!'+start+'/*.html', '!'+start+'/*.jade'])
    //TODO Inject uglify and minify
      .pipe(gulp.dest(end));
    gutil.log('--Finished Rest');
  }
}

function compile(ops) {

  var doJade = ops.jade || ops.all || false;
  var doRest = ops.rest || ops.all || false;
  var doCss  = ops.css  || ops.all || false;

  fs.readdir(__dirname+'/templates', function(err, files) {
    if(err)
      return gutil.log('Error while reading files from: ' + __dirname);
    // Read Each File that starts with '_'
    files
      //file.startsWith('_')
      .filter((file) => ['template.jade'].indexOf(file) === -1 )
      .forEach((file) => {
        gutil.log('File to be Processed: ' + file);
        processTemplate(file, ops);
      });
      gutil.log('Finished Compiling Templates!');
  });
}

function transfer() {
  gutil.log('Transfering Assets...');
  gulp.src('assets/**/*.*')
    .pipe(gulp.dest('public/assets'));
}

gulp.task('jade', function() {
  compile({jade: true});
});

gulp.task('css', function() {
  compile({css: true})
});

gulp.task('build', function() {
  compile({all: true});

});

gulp.task('release', function() {
  compile({all: true});
  transfer();
});

gulp.task('browserSync', function() {
    browserSync.init({
      server: {
        baseDir: './public'
      }
    });
    gulp.watch('public/**/*.*', browserSync.reload);
    //gulp.watch(['./**/*.css', './**/*.jade', '!public'], ['build'])
    // Everything that is a jade file should be rebuilt
    gulp.watch(['templates/**/*.jade'], ['jade']);
    // Everything that is note a jade file should be passed
    gulp.watch(['templates/**/*.*', '!templates/**/*.jade', '!templates/**/*.html'], function(event) {
      // Get Name Of the Template Page
      var rel = event.path.substring(__dirname.length+'/templates/'.length);
      rel = rel.split('/')[0];
      gutil.log(rel);
      processTemplate(rel, {rest: true});
    });
    gulp.watch(routes.assets)
});

gulp.task('run', ['build', 'browserSync']);

gulp.task('clean', function() {
  gutil.log('Cleaning...');
  // Remove everything in Public/
  // Remove every .html from templates
});

gulp.task('default', ['build']);
<|endoftext|>


<commit_before>require('../polyfills/array');

var myBooksController = function (User, Book, Update) {
  var put = function (req, res) {
    var user = req.user;

    if (!user) {
      res.status(401);
      res.json({
        message: 'Unauthorized user'
      });
      return;
    }

    var obj = {
      bookId: req.body.bookId,
      bookStatus: req.body.bookStatus
    };
    Book.findById(obj.bookId, function (err, book) {
      if (err) {
        // res.status(500).json(err);
        throw err;
      }
      if (!book) {
        res.status(404).json({
          message: 'No book found'
        });
        return;
      }

      var oldStatus = 'not reading';

      ['booksToRead', 'booksCurrentlyReading', 'booksRead'].forEach(function (name) {
        var index = user[name].findIndex(function (myBook) {
          return myBook.id === book._id.toString();
        });
        if (index >= 0) {
          user[name].splice(index, 1);
          oldStatus = name;
        }
      });

      var statusMap = {
        'want-to-read': 'booksToRead',
        'currently-reading': 'booksCurrentlyReading',
        'read': 'booksRead'
      };

      user[statusMap[obj.bookStatus]].push({
        id: book._id,
        updateDate: new Date()
      });

      var newStatus = statusMap[obj.bookStatus];

      User.update({
        _id: user._id
      }, {
        booksToRead: user.booksToRead,
        booksCurrentlyReading: user.booksCurrentlyReading,
        booksRead: user.booksRead
      }, function () {

        /*

{{text}}

        book: {{book.title}}
        by {{user.username}}
        */

        var newUpdate = new Update({
          text: user.username + ' changed ' + book.title + ' \'s status to ' + newStatus,
          date: new Date(),
          user: {
            username: user.username,
            id: user._id
          },
          book: {
            id: book.id,
            title: book.title,
            status: newStatus
          }
        });

        newUpdate.save(function (err, update) {

          res.json(true);
        });

      });
    });
  };

  var get = function (req, res) {
    var user = req.user;
    if (!user) {
      res.status(401);
      res.json({
        message: 'Unauthorized user'
      });
      return;
    }
    var books = user.booksToRead.concat(user.booksCurrentlyReading).concat(user.booksRead);

    var bookIds = books.map(function (book) {
      return book.id;
    });
    Book.find({
      _id: {
        "$in": bookIds
      }
    }, function (err, books) {
      if (err) {
        throw err;
      }
      //
      // books = books.map(function(book){
      //   if(user.booksToRead.any(function(dbBook){
      //     return dbBook.id === book.id;
      //   })){
      //     book.status = 'want-to-read';
      //   }
      // });
      res.json(books);
    });
  };

  return {
    put: put,
    get: get
  };
};

module.exports = myBooksController;
<commit_msg>Added status to each book in user collections<commit_after>require('../polyfills/array');

var myBooksController = function (User, Book, Update) {
  var put = function (req, res) {
    var user = req.user;

    if (!user) {
      res.status(401);
      res.json({
        message: 'Unauthorized user'
      });
      return;
    }

    var obj = {
      bookId: req.body.bookId,
      bookStatus: req.body.bookStatus
    };
    Book.findById(obj.bookId, function (err, book) {
      if (err) {
        // res.status(500).json(err);
        throw err;
      }
      if (!book) {
        res.status(404).json({
          message: 'No book found'
        });
        return;
      }

      var oldStatus = 'not reading';

      ['booksToRead', 'booksCurrentlyReading', 'booksRead'].forEach(function (name) {
        var index = user[name].findIndex(function (myBook) {
          return myBook.id === book._id.toString();
        });
        if (index >= 0) {
          user[name].splice(index, 1);
          oldStatus = name;
        }
      });

      var statusMap = {
        'want-to-read': 'booksToRead',
        'currently-reading': 'booksCurrentlyReading',
        'read': 'booksRead'
      };

      var newStatus = statusMap[obj.bookStatus];

      user[statusMap[obj.bookStatus]].push({
        id: book._id,
        updateDate: new Date(),
        status: newStatus
      });

      User.update({
        _id: user._id
      }, {
        booksToRead: user.booksToRead,
        booksCurrentlyReading: user.booksCurrentlyReading,
        booksRead: user.booksRead
      }, function () {

        /*

{{text}}

        book: {{book.title}}
        by {{user.username}}
        */

        var newUpdate = new Update({
          text: user.username + ' changed ' + book.title + ' \'s status to ' + newStatus,
          date: new Date(),
          user: {
            username: user.username,
            id: user._id
          },
          book: {
            id: book.id,
            title: book.title,
            status: newStatus
          }
        });

        newUpdate.save(function (err, update) {

          res.json(true);
        });

      });
    });
  };

  var get = function (req, res) {
    var user = req.user;
    if (!user) {
      res.status(401);
      res.json({
        message: 'Unauthorized user'
      });
      return;
    }
    var books = user.booksToRead.concat(user.booksCurrentlyReading).concat(user.booksRead);

    var bookIds = books.map(function (book) {
      return book.id;
    });
    Book.find({
      _id: {
        "$in": bookIds
      }
    }, function (err, books) {
      if (err) {
        throw err;
      }
      //
      // books = books.map(function(book){
      //   if(user.booksToRead.any(function(dbBook){
      //     return dbBook.id === book.id;
      //   })){
      //     book.status = 'want-to-read';
      //   }
      // });
      res.json(books);
    });
  };

  return {
    put: put,
    get: get
  };
};

module.exports = myBooksController;<|endoftext|>