<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

require('@babel/polyfill');

const CodegenRunner = require('../codegen/CodegenRunner');
const ConsoleReporter = require('../reporters/GraphQLConsoleReporter');
const DotGraphQLParser = require('../core/DotGraphQLParser');
const WatchmanClient = require('../core/GraphQLWatchmanClient');

const RelaySourceModuleParser = require('../core/RelaySourceModuleParser');
const RelayFileWriter = require('../codegen/RelayFileWriter');
const RelayIRTransforms = require('../core/RelayIRTransforms');
const RelayLanguagePluginJavaScript = require('../language/javascript/RelayLanguagePluginJavaScript');

const crypto = require('crypto');
const fs = require('fs');
const invariant = require('invariant');
const path = require('path');

const {
  buildASTSchema,
  buildClientSchema,
  parse,
  printSchema,
} = require('graphql');

const {
  commonTransforms,
  codegenTransforms,
  fragmentTransforms,
  printTransforms,
  queryTransforms,
  schemaExtensions,
} = RelayIRTransforms;

import type {ScalarTypeMapping} from '../language/javascript/RelayFlowTypeTransformers';
import type {WriteFilesOptions} from '../codegen/CodegenRunner';
import type {GraphQLSchema} from 'graphql';
import type {
  PluginInitializer,
  PluginInterface,
} from '../language/RelayLanguagePluginInterface';

export type Config = {|
  schema: string,
  src: string,
  extensions: Array<string>,
  include: Array<string>,
  exclude: Array<string>,
  verbose: boolean,
  watchman: boolean,
  watch?: ?boolean,
  validate: boolean,
  quiet: boolean,
  persistOutput?: ?string,
  noFutureProofEnums: boolean,
  language: string | PluginInitializer,
  persistFunction?: ?string | ?((text: string) => Promise<string>),
  artifactDirectory?: ?string,
  customScalars?: ScalarTypeMapping,
|};

function buildWatchExpression(config: {
  extensions: Array<string>,
  include: Array<string>,
  exclude: Array<string>,
}) {
  return [
    'allof',
    ['type', 'f'],
    ['anyof', ...config.extensions.map(ext => ['suffix', ext])],
    [
      'anyof',
      ...config.include.map(include => ['match', include, 'wholename']),
    ],
    ...config.exclude.map(exclude => ['not', ['match', exclude, 'wholename']]),
  ];
}

function getFilepathsFromGlob(
  baseDir,
  config: {
    extensions: Array<string>,
    include: Array<string>,
    exclude: Array<string>,
  },
): Array<string> {
  const {extensions, include, exclude} = config;
  const patterns = include.map(inc => `${inc}/*.+(${extensions.join('|')})`);

  const glob = require('fast-glob');
  return glob.sync(patterns, {
    cwd: baseDir,
    ignore: exclude,
  });
}

type LanguagePlugin = PluginInitializer | {default: PluginInitializer};

/**
 * Unless the requested plugin is the builtin `javascript` one, import a
 * language plugin as either a CommonJS or ES2015 module.
 *
 * When importing, first check if it’s a path to an existing file, otherwise
 * assume it’s a package and prepend the plugin namespace prefix.
 *
 * Make sure to always use Node's `require` function, which otherwise would get
 * replaced with `__webpack_require__` when bundled using webpack, by using
 * `eval` to get it at runtime.
 */
function getLanguagePlugin(
  language: string | PluginInitializer,
): PluginInterface {
  if (language === 'javascript') {
    return RelayLanguagePluginJavaScript();
  } else {
    let languagePlugin: LanguagePlugin;
    if (typeof language === 'string') {
      const pluginPath = path.resolve(process.cwd(), language);
      const requirePath = fs.existsSync(pluginPath)
        ? pluginPath
        : `relay-compiler-language-${language}`;
      try {
        // eslint-disable-next-line no-eval
        languagePlugin = eval('require')(requirePath);
        if (languagePlugin.default) {
          languagePlugin = languagePlugin.default;
        }
      } catch (err) {
        const e = new Error(
          `Unable to load language plugin ${requirePath}: ${err.message}`,
        );
        e.stack = err.stack;
        throw e;
      }
    } else {
      languagePlugin = language;
    }
    if (languagePlugin.default) {
      // $FlowFixMe - Flow no longer considers statics of functions as any
      languagePlugin = languagePlugin.default;
    }
    if (typeof languagePlugin === 'function') {
      // $FlowFixMe
      return languagePlugin();
    } else {
      throw new Error('Expected plugin to be a initializer function.');
    }
  }
}

function getPersistQueryFunction(
  config: Config,
): ?(text: string) => Promise<string> {
  const configValue = config.persistFunction;
  if (configValue == null) {
    return null;
  } else if (typeof configValue === 'string') {
    try {
      // eslint-disable-next-line no-eval
      const persistFunction = eval('require')(
        path.resolve(process.cwd(), configValue),
      );
      if (persistFunction.default) {
        return persistFunction.default;
      }
      return persistFunction;
    } catch (err) {
      const e = new Error(
        `Unable to load persistFunction ${configValue}: ${err.message}`,
      );
      e.stack = err.stack;
      throw e;
    }
  } else if (typeof configValue === 'function') {
    return configValue;
  } else {
    throw new Error(
      'Expected persistFunction to be a path string or a function.',
    );
  }
}

async function main(config: Config) {
  if (config.verbose && config.quiet) {
    throw new Error("I can't be quiet and verbose at the same time");
  }

  config = getPathBasedConfig(config);
  config = await getWatchConfig(config);

  // Use function from module.exports to be able to mock it for tests
  const codegenRunner = module.exports.getCodegenRunner(config);

  const result = config.watch
    ? await codegenRunner.watchAll()
    : await codegenRunner.compileAll();

  if (result === 'ERROR') {
    process.exit(100);
  }
  if (config.validate && result !== 'NO_CHANGES') {
    process.exit(101);
  }
}

function getPathBasedConfig(config: Config) {
  const schema = path.resolve(process.cwd(), config.schema);
  if (!fs.existsSync(schema)) {
    throw new Error(`--schema path does not exist: ${schema}`);
  }

  const src = path.resolve(process.cwd(), config.src);
  if (!fs.existsSync(src)) {
    throw new Error(`--src path does not exist: ${src}`);
  }

  let persistOutput = config.persistOutput;
  if (typeof persistOutput === 'string') {
    persistOutput = path.resolve(process.cwd(), persistOutput);
    const persistOutputDir = path.dirname(persistOutput);
    if (!fs.existsSync(persistOutputDir)) {
      throw new Error(`--persistOutput path does not exist: ${persistOutput}`);
    }
  }

  return {...config, schema, src, persistOutput};
}

async function getWatchConfig(config: Config): Promise<Config> {
  const watchman = config.watchman && (await WatchmanClient.isAvailable());

  if (config.watch) {
    if (!watchman) {
      throw new Error('Watchman is required to watch for changes.');
    }
    if (!module.exports.hasWatchmanRootFile(config.src)) {
      throw new Error(
        `
--watch requires that the src directory have a valid watchman "root" file.

Root files can include:
- A .git/ Git folder
- A .hg/ Mercurial folder
- A .watchmanconfig file

Ensure that one such file exists in ${config.src} or its parents.
      `.trim(),
      );
    }
  } else if (watchman && !config.validate) {
    // eslint-disable-next-line no-console
    console.log('HINT: pass --watch to keep watching for changes.');
  }

  return {...config, watchman};
}

function getCodegenRunner(config: Config): CodegenRunner {
  const reporter = new ConsoleReporter({
    verbose: config.verbose,
    quiet: config.quiet,
  });
  const schema = getSchema(config.schema);
  const languagePlugin = getLanguagePlugin(config.language);
  const persistQueryFunction = getPersistQueryFunction(config);
  const inputExtensions = config.extensions || languagePlugin.inputExtensions;
  const outputExtension = languagePlugin.outputExtension;
  const sourceParserName = inputExtensions.join('/');
  const sourceWriterName = outputExtension;
  const sourceModuleParser = RelaySourceModuleParser(
    languagePlugin.findGraphQLTags,
  );
  const providedArtifactDirectory = config.artifactDirectory;
  const artifactDirectory =
    providedArtifactDirectory != null
      ? path.resolve(process.cwd(), providedArtifactDirectory)
      : null;
  const generatedDirectoryName = artifactDirectory || '__generated__';
  const sourceSearchOptions = {
    extensions: inputExtensions,
    include: config.include,
    exclude: ['**/*.graphql.*', ...config.exclude],
  };
  const graphqlSearchOptions = {
    extensions: ['graphql'],
    include: config.include,
    exclude: [path.relative(config.src, config.schema)].concat(config.exclude),
  };
  const parserConfigs = {
    [sourceParserName]: {
      baseDir: config.src,
      getFileFilter: sourceModuleParser.getFileFilter,
      getParser: sourceModuleParser.getParser,
      getSchema: () => schema,
      watchmanExpression: config.watchman
        ? buildWatchExpression(sourceSearchOptions)
        : null,
      filepaths: config.watchman
        ? null
        : getFilepathsFromGlob(config.src, sourceSearchOptions),
    },
    graphql: {
      baseDir: config.src,
      getParser: DotGraphQLParser.getParser,
      getSchema: () => schema,
      watchmanExpression: config.watchman
        ? buildWatchExpression(graphqlSearchOptions)
        : null,
      filepaths: config.watchman
        ? null
        : getFilepathsFromGlob(config.src, graphqlSearchOptions),
    },
  };
  const writerConfigs = {
    [sourceWriterName]: {
      writeFiles: getRelayFileWriter(
        config.src,
        languagePlugin,
        config.noFutureProofEnums,
        artifactDirectory,
        config.persistOutput,
        config.customScalars,
        persistQueryFunction,
      ),
      isGeneratedFile: (filePath: string) =>
        filePath.endsWith('.graphql.' + outputExtension) &&
        filePath.includes(generatedDirectoryName),
      parser: sourceParserName,
      baseParsers: ['graphql'],
    },
  };
  const codegenRunner = new CodegenRunner({
    reporter,
    parserConfigs,
    writerConfigs,
    onlyValidate: config.validate,
    // TODO: allow passing in a flag or detect?
    sourceControl: null,
  });
  return codegenRunner;
}

function defaultPersistFunction(text: string): Promise<string> {
  const hasher = crypto.createHash('md5');
  hasher.update(text);
  const id = hasher.digest('hex');
  return Promise.resolve(id);
}

function getRelayFileWriter(
  baseDir: string,
  languagePlugin: PluginInterface,
  noFutureProofEnums: boolean,
  outputDir?: ?string,
  persistedQueryPath?: ?string,
  customScalars?: ScalarTypeMapping,
  persistFunction?: ?(text: string) => Promise<string>,
) {
  return async ({
    onlyValidate,
    schema,
    documents,
    baseDocuments,
    sourceControl,
    reporter,
  }: WriteFilesOptions) => {
    let persistQuery;
    let queryMap;
    if (persistFunction != null || persistedQueryPath != null) {
      queryMap = new Map();
      const persistImplmentation = persistFunction || defaultPersistFunction;
      persistQuery = async (text: string) => {
        const id = await persistImplmentation(text);
        invariant(
          typeof id === 'string',
          'Expected persist function to return a string, got `%s`.',
          id,
        );
        queryMap.set(id, text);
        return id;
      };
    }
    const results = await RelayFileWriter.writeAll({
      config: {
        baseDir,
        compilerTransforms: {
          commonTransforms,
          codegenTransforms,
          fragmentTransforms,
          printTransforms,
          queryTransforms,
        },
        customScalars: customScalars || {},
        formatModule: languagePlugin.formatModule,
        optionalInputFieldsForFlow: [],
        schemaExtensions,
        useHaste: false,
        noFutureProofEnums,
        extension: languagePlugin.outputExtension,
        typeGenerator: languagePlugin.typeGenerator,
        outputDir,
        persistQuery,
      },
      onlyValidate,
      schema,
      baseDocuments,
      documents,
      reporter,
      sourceControl,
    });
    if (queryMap != null && persistedQueryPath != null) {
      const object = {};
      for (const [key, value] of queryMap.entries()) {
        object[key] = value;
      }
      const data = JSON.stringify(object, null, 2);
      fs.writeFileSync(persistedQueryPath, data, 'utf8');
    }
    return results;
  };
}

function getSchema(schemaPath: string): GraphQLSchema {
  try {
    let source = fs.readFileSync(schemaPath, 'utf8');
    if (path.extname(schemaPath) === '.json') {
      source = printSchema(buildClientSchema(JSON.parse(source).data));
    }
    source = `
  directive @include(if: Boolean) on FRAGMENT_SPREAD | FIELD | INLINE_FRAGMENT
  directive @skip(if: Boolean) on FRAGMENT_SPREAD | FIELD | INLINE_FRAGMENT

  ${source}
  `;
    return buildASTSchema(parse(source), {assumeValid: true});
  } catch (error) {
    throw new Error(
      `
Error loading schema. Expected the schema to be a .graphql or a .json
file, describing your GraphQL server's API. Error detail:

${error.stack}
    `.trim(),
    );
  }
}

// Ensure that a watchman "root" file exists in the given directory
// or a parent so that it can be watched
const WATCHMAN_ROOT_FILES = ['.git', '.hg', '.watchmanconfig'];
function hasWatchmanRootFile(testPath: string): boolean {
  while (path.dirname(testPath) !== testPath) {
    if (
      WATCHMAN_ROOT_FILES.some(file => {
        return fs.existsSync(path.join(testPath, file));
      })
    ) {
      return true;
    }
    testPath = path.dirname(testPath);
  }
  return false;
}

module.exports = {
  getCodegenRunner,
  getLanguagePlugin,
  getWatchConfig,
  hasWatchmanRootFile,
  main,
};
<commit_msg>avoid dependency from RelayCompilerMain to @babel/polyfill<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

const CodegenRunner = require('../codegen/CodegenRunner');
const ConsoleReporter = require('../reporters/GraphQLConsoleReporter');
const DotGraphQLParser = require('../core/DotGraphQLParser');
const RelayFileWriter = require('../codegen/RelayFileWriter');
const RelayIRTransforms = require('../core/RelayIRTransforms');
const RelayLanguagePluginJavaScript = require('../language/javascript/RelayLanguagePluginJavaScript');
const RelaySourceModuleParser = require('../core/RelaySourceModuleParser');
const WatchmanClient = require('../core/GraphQLWatchmanClient');

const crypto = require('crypto');
const fs = require('fs');
const invariant = require('invariant');
const path = require('path');

const {
  buildASTSchema,
  buildClientSchema,
  parse,
  printSchema,
} = require('graphql');

const {
  commonTransforms,
  codegenTransforms,
  fragmentTransforms,
  printTransforms,
  queryTransforms,
  schemaExtensions,
} = RelayIRTransforms;

import type {ScalarTypeMapping} from '../language/javascript/RelayFlowTypeTransformers';
import type {WriteFilesOptions} from '../codegen/CodegenRunner';
import type {GraphQLSchema} from 'graphql';
import type {
  PluginInitializer,
  PluginInterface,
} from '../language/RelayLanguagePluginInterface';

export type Config = {|
  schema: string,
  src: string,
  extensions: Array<string>,
  include: Array<string>,
  exclude: Array<string>,
  verbose: boolean,
  watchman: boolean,
  watch?: ?boolean,
  validate: boolean,
  quiet: boolean,
  persistOutput?: ?string,
  noFutureProofEnums: boolean,
  language: string | PluginInitializer,
  persistFunction?: ?string | ?((text: string) => Promise<string>),
  artifactDirectory?: ?string,
  customScalars?: ScalarTypeMapping,
|};

function buildWatchExpression(config: {
  extensions: Array<string>,
  include: Array<string>,
  exclude: Array<string>,
}) {
  return [
    'allof',
    ['type', 'f'],
    ['anyof', ...config.extensions.map(ext => ['suffix', ext])],
    [
      'anyof',
      ...config.include.map(include => ['match', include, 'wholename']),
    ],
    ...config.exclude.map(exclude => ['not', ['match', exclude, 'wholename']]),
  ];
}

function getFilepathsFromGlob(
  baseDir,
  config: {
    extensions: Array<string>,
    include: Array<string>,
    exclude: Array<string>,
  },
): Array<string> {
  const {extensions, include, exclude} = config;
  const patterns = include.map(inc => `${inc}/*.+(${extensions.join('|')})`);

  const glob = require('fast-glob');
  return glob.sync(patterns, {
    cwd: baseDir,
    ignore: exclude,
  });
}

type LanguagePlugin = PluginInitializer | {default: PluginInitializer};

/**
 * Unless the requested plugin is the builtin `javascript` one, import a
 * language plugin as either a CommonJS or ES2015 module.
 *
 * When importing, first check if it’s a path to an existing file, otherwise
 * assume it’s a package and prepend the plugin namespace prefix.
 *
 * Make sure to always use Node's `require` function, which otherwise would get
 * replaced with `__webpack_require__` when bundled using webpack, by using
 * `eval` to get it at runtime.
 */
function getLanguagePlugin(
  language: string | PluginInitializer,
): PluginInterface {
  if (language === 'javascript') {
    return RelayLanguagePluginJavaScript();
  } else {
    let languagePlugin: LanguagePlugin;
    if (typeof language === 'string') {
      const pluginPath = path.resolve(process.cwd(), language);
      const requirePath = fs.existsSync(pluginPath)
        ? pluginPath
        : `relay-compiler-language-${language}`;
      try {
        // eslint-disable-next-line no-eval
        languagePlugin = eval('require')(requirePath);
        if (languagePlugin.default) {
          languagePlugin = languagePlugin.default;
        }
      } catch (err) {
        const e = new Error(
          `Unable to load language plugin ${requirePath}: ${err.message}`,
        );
        e.stack = err.stack;
        throw e;
      }
    } else {
      languagePlugin = language;
    }
    if (languagePlugin.default) {
      // $FlowFixMe - Flow no longer considers statics of functions as any
      languagePlugin = languagePlugin.default;
    }
    if (typeof languagePlugin === 'function') {
      // $FlowFixMe
      return languagePlugin();
    } else {
      throw new Error('Expected plugin to be a initializer function.');
    }
  }
}

function getPersistQueryFunction(
  config: Config,
): ?(text: string) => Promise<string> {
  const configValue = config.persistFunction;
  if (configValue == null) {
    return null;
  } else if (typeof configValue === 'string') {
    try {
      // eslint-disable-next-line no-eval
      const persistFunction = eval('require')(
        path.resolve(process.cwd(), configValue),
      );
      if (persistFunction.default) {
        return persistFunction.default;
      }
      return persistFunction;
    } catch (err) {
      const e = new Error(
        `Unable to load persistFunction ${configValue}: ${err.message}`,
      );
      e.stack = err.stack;
      throw e;
    }
  } else if (typeof configValue === 'function') {
    return configValue;
  } else {
    throw new Error(
      'Expected persistFunction to be a path string or a function.',
    );
  }
}

async function main(config: Config) {
  if (config.verbose && config.quiet) {
    throw new Error("I can't be quiet and verbose at the same time");
  }

  config = getPathBasedConfig(config);
  config = await getWatchConfig(config);

  // Use function from module.exports to be able to mock it for tests
  const codegenRunner = module.exports.getCodegenRunner(config);

  const result = config.watch
    ? await codegenRunner.watchAll()
    : await codegenRunner.compileAll();

  if (result === 'ERROR') {
    process.exit(100);
  }
  if (config.validate && result !== 'NO_CHANGES') {
    process.exit(101);
  }
}

function getPathBasedConfig(config: Config) {
  const schema = path.resolve(process.cwd(), config.schema);
  if (!fs.existsSync(schema)) {
    throw new Error(`--schema path does not exist: ${schema}`);
  }

  const src = path.resolve(process.cwd(), config.src);
  if (!fs.existsSync(src)) {
    throw new Error(`--src path does not exist: ${src}`);
  }

  let persistOutput = config.persistOutput;
  if (typeof persistOutput === 'string') {
    persistOutput = path.resolve(process.cwd(), persistOutput);
    const persistOutputDir = path.dirname(persistOutput);
    if (!fs.existsSync(persistOutputDir)) {
      throw new Error(`--persistOutput path does not exist: ${persistOutput}`);
    }
  }

  return {...config, schema, src, persistOutput};
}

async function getWatchConfig(config: Config): Promise<Config> {
  const watchman = config.watchman && (await WatchmanClient.isAvailable());

  if (config.watch) {
    if (!watchman) {
      throw new Error('Watchman is required to watch for changes.');
    }
    if (!module.exports.hasWatchmanRootFile(config.src)) {
      throw new Error(
        `
--watch requires that the src directory have a valid watchman "root" file.

Root files can include:
- A .git/ Git folder
- A .hg/ Mercurial folder
- A .watchmanconfig file

Ensure that one such file exists in ${config.src} or its parents.
      `.trim(),
      );
    }
  } else if (watchman && !config.validate) {
    // eslint-disable-next-line no-console
    console.log('HINT: pass --watch to keep watching for changes.');
  }

  return {...config, watchman};
}

function getCodegenRunner(config: Config): CodegenRunner {
  const reporter = new ConsoleReporter({
    verbose: config.verbose,
    quiet: config.quiet,
  });
  const schema = getSchema(config.schema);
  const languagePlugin = getLanguagePlugin(config.language);
  const persistQueryFunction = getPersistQueryFunction(config);
  const inputExtensions = config.extensions || languagePlugin.inputExtensions;
  const outputExtension = languagePlugin.outputExtension;
  const sourceParserName = inputExtensions.join('/');
  const sourceWriterName = outputExtension;
  const sourceModuleParser = RelaySourceModuleParser(
    languagePlugin.findGraphQLTags,
  );
  const providedArtifactDirectory = config.artifactDirectory;
  const artifactDirectory =
    providedArtifactDirectory != null
      ? path.resolve(process.cwd(), providedArtifactDirectory)
      : null;
  const generatedDirectoryName = artifactDirectory || '__generated__';
  const sourceSearchOptions = {
    extensions: inputExtensions,
    include: config.include,
    exclude: ['**/*.graphql.*', ...config.exclude],
  };
  const graphqlSearchOptions = {
    extensions: ['graphql'],
    include: config.include,
    exclude: [path.relative(config.src, config.schema)].concat(config.exclude),
  };
  const parserConfigs = {
    [sourceParserName]: {
      baseDir: config.src,
      getFileFilter: sourceModuleParser.getFileFilter,
      getParser: sourceModuleParser.getParser,
      getSchema: () => schema,
      watchmanExpression: config.watchman
        ? buildWatchExpression(sourceSearchOptions)
        : null,
      filepaths: config.watchman
        ? null
        : getFilepathsFromGlob(config.src, sourceSearchOptions),
    },
    graphql: {
      baseDir: config.src,
      getParser: DotGraphQLParser.getParser,
      getSchema: () => schema,
      watchmanExpression: config.watchman
        ? buildWatchExpression(graphqlSearchOptions)
        : null,
      filepaths: config.watchman
        ? null
        : getFilepathsFromGlob(config.src, graphqlSearchOptions),
    },
  };
  const writerConfigs = {
    [sourceWriterName]: {
      writeFiles: getRelayFileWriter(
        config.src,
        languagePlugin,
        config.noFutureProofEnums,
        artifactDirectory,
        config.persistOutput,
        config.customScalars,
        persistQueryFunction,
      ),
      isGeneratedFile: (filePath: string) =>
        filePath.endsWith('.graphql.' + outputExtension) &&
        filePath.includes(generatedDirectoryName),
      parser: sourceParserName,
      baseParsers: ['graphql'],
    },
  };
  const codegenRunner = new CodegenRunner({
    reporter,
    parserConfigs,
    writerConfigs,
    onlyValidate: config.validate,
    // TODO: allow passing in a flag or detect?
    sourceControl: null,
  });
  return codegenRunner;
}

function defaultPersistFunction(text: string): Promise<string> {
  const hasher = crypto.createHash('md5');
  hasher.update(text);
  const id = hasher.digest('hex');
  return Promise.resolve(id);
}

function getRelayFileWriter(
  baseDir: string,
  languagePlugin: PluginInterface,
  noFutureProofEnums: boolean,
  outputDir?: ?string,
  persistedQueryPath?: ?string,
  customScalars?: ScalarTypeMapping,
  persistFunction?: ?(text: string) => Promise<string>,
) {
  return async ({
    onlyValidate,
    schema,
    documents,
    baseDocuments,
    sourceControl,
    reporter,
  }: WriteFilesOptions) => {
    let persistQuery;
    let queryMap;
    if (persistFunction != null || persistedQueryPath != null) {
      queryMap = new Map();
      const persistImplmentation = persistFunction || defaultPersistFunction;
      persistQuery = async (text: string) => {
        const id = await persistImplmentation(text);
        invariant(
          typeof id === 'string',
          'Expected persist function to return a string, got `%s`.',
          id,
        );
        queryMap.set(id, text);
        return id;
      };
    }
    const results = await RelayFileWriter.writeAll({
      config: {
        baseDir,
        compilerTransforms: {
          commonTransforms,
          codegenTransforms,
          fragmentTransforms,
          printTransforms,
          queryTransforms,
        },
        customScalars: customScalars || {},
        formatModule: languagePlugin.formatModule,
        optionalInputFieldsForFlow: [],
        schemaExtensions,
        useHaste: false,
        noFutureProofEnums,
        extension: languagePlugin.outputExtension,
        typeGenerator: languagePlugin.typeGenerator,
        outputDir,
        persistQuery,
      },
      onlyValidate,
      schema,
      baseDocuments,
      documents,
      reporter,
      sourceControl,
    });
    if (queryMap != null && persistedQueryPath != null) {
      const object = {};
      for (const [key, value] of queryMap.entries()) {
        object[key] = value;
      }
      const data = JSON.stringify(object, null, 2);
      fs.writeFileSync(persistedQueryPath, data, 'utf8');
    }
    return results;
  };
}

function getSchema(schemaPath: string): GraphQLSchema {
  try {
    let source = fs.readFileSync(schemaPath, 'utf8');
    if (path.extname(schemaPath) === '.json') {
      source = printSchema(buildClientSchema(JSON.parse(source).data));
    }
    source = `
  directive @include(if: Boolean) on FRAGMENT_SPREAD | FIELD | INLINE_FRAGMENT
  directive @skip(if: Boolean) on FRAGMENT_SPREAD | FIELD | INLINE_FRAGMENT

  ${source}
  `;
    return buildASTSchema(parse(source), {assumeValid: true});
  } catch (error) {
    throw new Error(
      `
Error loading schema. Expected the schema to be a .graphql or a .json
file, describing your GraphQL server's API. Error detail:

${error.stack}
    `.trim(),
    );
  }
}

// Ensure that a watchman "root" file exists in the given directory
// or a parent so that it can be watched
const WATCHMAN_ROOT_FILES = ['.git', '.hg', '.watchmanconfig'];
function hasWatchmanRootFile(testPath: string): boolean {
  while (path.dirname(testPath) !== testPath) {
    if (
      WATCHMAN_ROOT_FILES.some(file => {
        return fs.existsSync(path.join(testPath, file));
      })
    ) {
      return true;
    }
    testPath = path.dirname(testPath);
  }
  return false;
}

module.exports = {
  getCodegenRunner,
  getLanguagePlugin,
  getWatchConfig,
  hasWatchmanRootFile,
  main,
};
<|endoftext|>


<commit_before>var rackDragOpt = {
	containment: '#rackContainer',
	scroll: true,
	snap: '.rackG',
	snapMode: 'outer',
	stack: '.rackG',
	revert: 'invalid',
	grid: [ 10, 10 ],
	stop: function(event, ui) {
		$(this).draggable('option', 'revert', 'invalid');
		var id = getExactId(ui.helper.find('.rackGform').find('div[id!=""]').attr('id'));
		ui.helper.find('#debb_configbundle_roomtype_racks_' + id + '_posx').val(ui.position.left);
		ui.helper.find('#debb_configbundle_roomtype_racks_' + id + '_posy').val(parseFloat(ui.helper.css('bottom')));
	}
},
	rackDropOpt = {
	greedy: true,
	tolerance: 'touch',
	drop: function(event, ui){
		ui.draggable.draggable('option', 'revert', true);
	}
};

function setStyleOfRack(newRack)
{
	if(typeof param == 'undefined')
	{
		var newRack = $(this);
	}
	if(newRack.hasClass('draftRack'))
	{
		newRack = $(this).clone().removeClass('draftRack').addClass('rackG');

		var id = 0;
		$('.rackGform').each(function()
		{
			if(getExactId($(this).find('div[id!=""]').attr('id')) > id)
			{
				id = getExactId($(this).children('div').attr('id'));
				id++;
			}
		});
		id++;

		var prototype = $('#rackContainer').attr('data-prototype'),
			newForm = prototype.replace(/__name__/g, id),
			newFormLi = $('

').append($(newForm).children('div')).before(' - ');
		newFormLi.find('#debb_configbundle_roomtype_racks_' + id + '_rack').val(newRack.attr('rackId'));
		newRack.append(newFormLi);

		newRack.appendTo('#rackContainer').draggable(rackDragOpt).droppable(rackDropOpt);
	}
	newRack.css('width', (parseFloat(newRack.attr('rackX')) < 1 ? 99 : parseFloat(newRack.attr('rackX')) * 100 - 1) + 'px');
	newRack.css('height', (parseFloat(newRack.attr('rackY')) < 1 ? 99 : parseFloat(newRack.attr('rackY')) * 100 - 1) + 'px');
	if(typeof newRack.attr('posx') != 'undefined')
	{
		newRack.css('left', (parseFloat(newRack.attr('posx')) < 0 ? 0 : parseFloat(newRack.attr('posx'))) + 'px');
		newRack.removeAttr('posx');
	}
	if(typeof newRack.attr('posy') != 'undefined')
	{
		newRack.css('bottom', (parseFloat(newRack.attr('posy')) < 0 ? $('#rackContainer').height() - newRack.outerHeight() : parseFloat(newRack.attr('posy'))) + 'px');
		newRack.removeAttr('posy');
	}
}

$(function()
{
	$('.draftRack').on('click', setStyleOfRack);
	// dynamic size for our room
	$('#rackContainer').resizable({
		grid: 10,
		stop: function( event, ui ) {
			$('#debb_configbundle_roomtype_sizeX').val(ui.helper.width());
			$('#debb_configbundle_roomtype_sizeY').val(ui.helper.height());
		}
	}).droppable({tolerance: 'fit'});
	$(document).on('click', '.removeRack', function(e)
	{
		e.preventDefault();
		$(this).parent('.rackG').remove();
	});
	// a single rack which we could move in our room
	$('.rackG').draggable(rackDragOpt).droppable(rackDropOpt);
	$('.rackG').each(setStyleOfRack);
});
<commit_msg>Fixed bug with integer and floats - Task #1606<commit_after>var rackDragOpt = {
	containment: '#rackContainer',
	scroll: true,
	snap: '.rackG',
	snapMode: 'outer',
	stack: '.rackG',
	revert: 'invalid',
	grid: [ 10, 10 ],
	stop: function(event, ui) {
		$(this).draggable('option', 'revert', 'invalid');
		var id = getExactId(ui.helper.find('.rackGform').find('div[id!=""]').attr('id'));
		ui.helper.find('#debb_configbundle_roomtype_racks_' + id + '_posx').val(ui.position.left);
		ui.helper.find('#debb_configbundle_roomtype_racks_' + id + '_posy').val(parseInt(ui.helper.css('bottom')));
	}
},
	rackDropOpt = {
	greedy: true,
	tolerance: 'touch',
	drop: function(event, ui){
		ui.draggable.draggable('option', 'revert', true);
	}
};

function setStyleOfRack(newRack)
{
	if(typeof param == 'undefined')
	{
		var newRack = $(this);
	}
	if(newRack.hasClass('draftRack'))
	{
		newRack = $(this).clone().removeClass('draftRack').addClass('rackG');

		var id = 0;
		$('.rackGform').each(function()
		{
			if(getExactId($(this).find('div[id!=""]').attr('id')) > id)
			{
				id = getExactId($(this).children('div').attr('id'));
				id++;
			}
		});
		id++;

		var prototype = $('#rackContainer').attr('data-prototype'),
			newForm = prototype.replace(/__name__/g, id),
			newFormLi = $('

').append($(newForm).children('div')).before(' - ');
		newFormLi.find('#debb_configbundle_roomtype_racks_' + id + '_rack').val(newRack.attr('rackId'));
		newRack.append(newFormLi);

		newRack.appendTo('#rackContainer').draggable(rackDragOpt).droppable(rackDropOpt);
	}
	newRack.css('width', (parseFloat(newRack.attr('rackX')) <= 0 ? 99 : parseFloat(newRack.attr('rackX')) * 100 - 1) + 'px');
	newRack.css('height', (parseFloat(newRack.attr('rackY')) <= 0 ? 99 : parseFloat(newRack.attr('rackY')) * 100 - 1) + 'px');
	if(typeof newRack.attr('posx') != 'undefined')
	{
		newRack.css('left', (parseInt(newRack.attr('posx')) < 0 ? 0 : parseInt(newRack.attr('posx'))) + 'px');
		newRack.removeAttr('posx');
	}
	if(typeof newRack.attr('posy') != 'undefined')
	{
		newRack.css('bottom', (parseInt(newRack.attr('posy')) < 0 ? $('#rackContainer').height() - newRack.outerHeight() : parseInt(newRack.attr('posy'))) + 'px');
		newRack.removeAttr('posy');
	}
}

$(function()
{
	$('.draftRack').on('click', setStyleOfRack);
	// dynamic size for our room
	$('#rackContainer').resizable({
		grid: 10,
		stop: function( event, ui ) {
			$('#debb_configbundle_roomtype_sizeX').val(ui.helper.width());
			$('#debb_configbundle_roomtype_sizeY').val(ui.helper.height());
		}
	}).droppable({tolerance: 'fit'});
	$(document).on('click', '.removeRack', function(e)
	{
		e.preventDefault();
		$(this).parent('.rackG').remove();
	});
	// a single rack which we could move in our room
	$('.rackG').draggable(rackDragOpt).droppable(rackDropOpt);
	$('.rackG').each(setStyleOfRack);
});
<|endoftext|>


<commit_before>var savedSeq = null;
$(document).ready(function()
{
	CKEDITOR.replace("ckeditor", { height: 300 });

	if($.query.seq != null)
		savedSeq = $.query.seq;

	$("#form").compile(function(param)
	{
		param.boardId = "qna";
		param.content = CKEDITOR.instances.ckeditor.getData();
		var result = null;
		if(savedSeq != null)
		{
			param.seq = savedSeq;
			param.status = 0;
			result = $.api.article.updateArticle(param);
		}
		else
		{
			result = $.api.article.writeArticle(param);
		}

		if(result != null)
		{
			if(result.code == -9998)
			{
				alert("권한이 없습니다");
			}
			else
			{
				location.href = "?body=qna";
			}
		}
	});
});<commit_msg>하비홈페이지수정<commit_after>var savedSeq = null;
$(document).ready(function()
{
	CKEDITOR.replace("ckeditor", { height: 300 });

	if($.query.seq != null)
		savedSeq = $.query.seq;

	$("#form").compile(function(param)
	{
		param.boardId = "qna";
		param.content = CKEDITOR.instances.ckeditor.getData();
		var result = null;
		if(savedSeq != null)
		{
			param.seq = savedSeq;
			result = $.api.article.updateArticle(param);
		}
		else
		{
			result = $.api.article.writeArticle(param);
		}

		if(result != null)
		{
			if(result.code == -9998)
			{
				alert("권한이 없습니다");
			}
			else
			{
				location.href = "?body=qna";
			}
		}
	});
});<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * 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.
 */
class ChartDirective {
  constructor() {
    return {
      restrict: 'E',
      template: '

',
      scope: {
        options: '=',
        type: '@',
        zoom: '@',
        height: '@',
        width: '@'
      },
      link: function (scope, element) {
        if (scope.type && scope.type.startsWith('area') && _.isArray(scope.options)) {
          initSynchronizedCharts();
        }

        setChartSize();

        let lastOptions;
        scope.$watch('options', function (newOptions) {
          executeDisplayChart(newOptions, element);
          lastOptions = newOptions;
        }, true);

        $(window).resize(function () {
          onResize();
        });

        scope.$root.$watch('reducedMode', function (reducedMode) {
          if (reducedMode !== undefined) {
            setTimeout(function () {
              onResize();
            });
          }
        });

        function onResize() {
          setChartSize();
          executeDisplayChart(lastOptions, element);
        }

        function setChartSize() {
          let chartElement = angular.element(element[0]);
          chartElement.css('height', scope.height || chartElement.parent().height());
          chartElement.css('width', scope.width || chartElement.parent().width());
        }

        function executeDisplayChart(newOptions, element) {
          if (_.isArray(newOptions)) {
            while (element[0].firstChild) {
              element[0].removeChild(element[0].firstChild);
            }

            _.forEach(newOptions, function (newOption) {
              let child = document.createElement('div');
              element[0].append(child);

              let childElement = angular.element(child);
              childElement.css('height', scope.height || childElement.parent().height());

              displayChart(newOption, child);
            });
          } else {
            displayChart(newOptions, element[0]);
          }
        }

        function initSynchronizedCharts() {
          let points = [];
          element.bind('mousemove touchmove touchstart', function (e) {
            let chart, i, event;

            for (i = 0; i < Highcharts.charts.length; i++) {
              chart = Highcharts.charts[i];
              if (chart) {
                event = chart.pointer.normalize(e.originalEvent);
                points = _.map(chart.series, function (serie) {
                  return serie.searchPoint(event, true);
                });
                points = _.filter(points, function (point) {
                  return point;
                });

                if (points.length && points[0] && points[0].series.area) {
                  points[0].highlight(e);
                }
              }
            }
          });
          Highcharts.Pointer.prototype.reset = function () {
            let chart;
            for (let i = 0; i < Highcharts.charts.length; i++) {
              chart = Highcharts.charts[i];
              if (chart) {
                chart.tooltip.hide(this);
                chart.xAxis[0].hideCrosshair();
              }
            }
          };
          Highcharts.Point.prototype.highlight = function (event) {
            if (points.length) {
              this.onMouseOver();
              this.series.chart.tooltip.refresh(points);
              this.series.chart.xAxis[0].drawCrosshair(event, this);
            }
          };
        }

        function syncExtremes(e) {
          let thisChart = this.chart;

          if (e.trigger !== 'syncExtremes') {
            Highcharts.each(Highcharts.charts, function (chart) {
              if (chart && chart !== thisChart) {
                if (chart.xAxis[0].setExtremes) {
                  chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {trigger: 'syncExtremes'});
                }
              }
            });
          }
        }

        function displayChart(newOptions, element) {
          if (newOptions) {
            if (newOptions.title) {
              newOptions.title.style = {
                'fontWeight': 'bold',
                'fontSize': '12px',
                'fontFamily': '"Helvetica Neue",Helvetica,Arial,sans-serif'
              };
              newOptions.title.align = 'left';
            } else {
              newOptions.title = {text: ''};
            }
            newOptions.yAxis = _.merge(newOptions.yAxis, {title: {text: ''}});
            newOptions.chart = {type: scope.type};
            if (scope.zoom) {
              newOptions.chart.zoomType = 'x';
            }
            newOptions.credits = {
              enabled: false
            };
            newOptions.series = _.sortBy(newOptions.series, 'name');

            _.forEach(newOptions.series, function (serie) {
              serie.data = _.sortBy(serie.data, 'name');
            });

            if (scope.type && scope.type.startsWith('area')) {
              newOptions.tooltip = {
                formatter: function () {
                  let s = '' + this.x + '';
                  if (_.filter(this.points, function (point) {
                      return point.y !== 0;
                    }).length) {
                    _.forEach(this.points, function (point) {
                      if (point.y) {
                        let name = ' ' + (point.series.options.labelPrefix ? point.series.options.labelPrefix + ' ' + point.series.name : point.series.name);
                        s += '
\u25CF' + name + ': ' + point.y + '';
                      }
                    });
                  }
                  return s;
                },
                shared: true
              };
              newOptions.plotOptions = _.merge(newOptions.plotOptions, {
                series: {
                  marker: {
                    enabled: false
                  },
                  fillOpacity: 0.1
                }
              });
              if (_.isArray(scope.options)) {
                newOptions.xAxis = _.merge(newOptions.xAxis, {crosshair: true, events: {setExtremes: syncExtremes}});
              }
            } else if (scope.type && scope.type === 'solidgauge') {
              newOptions = _.merge(newOptions, {
                pane: {
                  background: {
                    innerRadius: '80%',
                    outerRadius: '100%'
                  }
                },

                tooltip: {
                  enabled: false
                },

                yAxis: {
                  showFirstLabel: false,
                  showLastLabel: false,
                  min: 0,
                  max: 100,
                  stops: [
                    [0.1, '#55BF3B'], // green
                    [0.5, '#DDDF0D'], // yellow
                    [0.9, '#DF5353'] // red
                  ],
                  minorTickInterval: null,
                  tickAmount: 2
                },

                plotOptions: {
                  solidgauge: {
                    innerRadius: '80%',
                    outerRadius: '100%',
                    dataLabels: {
                      y: 30,
                      borderWidth: 0,
                      useHTML: true
                    }
                  }
                },
                series: [{
                  dataLabels: {
                    format: '
' +
                    '{y}%
' +
                    '' + newOptions.series[0].name + '' +
                    '
'
                  }
                }]
              });
            } else if (scope.type && scope.type === 'column') {
              if (scope.stacked) {
                newOptions.plotOptions = {
                  column: {
                    stacking: 'normal'
                  }
                };
              }
            }
            Highcharts.chart(element, newOptions);
          }
        }
      }
    };
  }
}

export default ChartDirective;
<commit_msg>fix(chart): replace append method by appendChild method to be cross browser compliant<commit_after>/*
 * Copyright (C) 2015 The Gravitee team (http://gravitee.io)
 *
 * 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.
 */
class ChartDirective {
  constructor() {
    return {
      restrict: 'E',
      template: '

',
      scope: {
        options: '=',
        type: '@',
        zoom: '@',
        height: '@',
        width: '@'
      },
      link: function (scope, element) {
        if (scope.type && scope.type.startsWith('area') && _.isArray(scope.options)) {
          initSynchronizedCharts();
        }

        setChartSize();

        let lastOptions;
        scope.$watch('options', function (newOptions) {
          executeDisplayChart(newOptions, element);
          lastOptions = newOptions;
        }, true);

        $(window).resize(function () {
          onResize();
        });

        scope.$root.$watch('reducedMode', function (reducedMode) {
          if (reducedMode !== undefined) {
            setTimeout(function () {
              onResize();
            });
          }
        });

        function onResize() {
          setChartSize();
          executeDisplayChart(lastOptions, element);
        }

        function setChartSize() {
          let chartElement = angular.element(element[0]);
          chartElement.css('height', scope.height || chartElement.parent().height());
          chartElement.css('width', scope.width || chartElement.parent().width());
        }

        function executeDisplayChart(newOptions, element) {
          if (_.isArray(newOptions)) {
            while (element[0].firstChild) {
              element[0].removeChild(element[0].firstChild);
            }

            _.forEach(newOptions, function (newOption) {
              let child = document.createElement('div');
              element[0].appendChild(child);

              let childElement = angular.element(child);
              childElement.css('height', scope.height || childElement.parent().height());

              displayChart(newOption, child);
            });
          } else {
            displayChart(newOptions, element[0]);
          }
        }

        function initSynchronizedCharts() {
          let points = [];
          element.bind('mousemove touchmove touchstart', function (e) {
            let chart, i, event;

            for (i = 0; i < Highcharts.charts.length; i++) {
              chart = Highcharts.charts[i];
              if (chart) {
                event = chart.pointer.normalize(e.originalEvent);
                points = _.map(chart.series, function (serie) {
                  return serie.searchPoint(event, true);
                });
                points = _.filter(points, function (point) {
                  return point;
                });

                if (points.length && points[0] && points[0].series.area) {
                  points[0].highlight(e);
                }
              }
            }
          });
          Highcharts.Pointer.prototype.reset = function () {
            let chart;
            for (let i = 0; i < Highcharts.charts.length; i++) {
              chart = Highcharts.charts[i];
              if (chart) {
                chart.tooltip.hide(this);
                chart.xAxis[0].hideCrosshair();
              }
            }
          };
          Highcharts.Point.prototype.highlight = function (event) {
            if (points.length) {
              this.onMouseOver();
              this.series.chart.tooltip.refresh(points);
              this.series.chart.xAxis[0].drawCrosshair(event, this);
            }
          };
        }

        function syncExtremes(e) {
          let thisChart = this.chart;

          if (e.trigger !== 'syncExtremes') {
            Highcharts.each(Highcharts.charts, function (chart) {
              if (chart && chart !== thisChart) {
                if (chart.xAxis[0].setExtremes) {
                  chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {trigger: 'syncExtremes'});
                }
              }
            });
          }
        }

        function displayChart(newOptions, element) {
          if (newOptions) {
            if (newOptions.title) {
              newOptions.title.style = {
                'fontWeight': 'bold',
                'fontSize': '12px',
                'fontFamily': '"Helvetica Neue",Helvetica,Arial,sans-serif'
              };
              newOptions.title.align = 'left';
            } else {
              newOptions.title = {text: ''};
            }
            newOptions.yAxis = _.merge(newOptions.yAxis, {title: {text: ''}});
            newOptions.chart = {type: scope.type};
            if (scope.zoom) {
              newOptions.chart.zoomType = 'x';
            }
            newOptions.credits = {
              enabled: false
            };
            newOptions.series = _.sortBy(newOptions.series, 'name');

            _.forEach(newOptions.series, function (serie) {
              serie.data = _.sortBy(serie.data, 'name');
            });

            if (scope.type && scope.type.startsWith('area')) {
              newOptions.tooltip = {
                formatter: function () {
                  let s = '' + this.x + '';
                  if (_.filter(this.points, function (point) {
                      return point.y !== 0;
                    }).length) {
                    _.forEach(this.points, function (point) {
                      if (point.y) {
                        let name = ' ' + (point.series.options.labelPrefix ? point.series.options.labelPrefix + ' ' + point.series.name : point.series.name);
                        s += '
\u25CF' + name + ': ' + point.y + '';
                      }
                    });
                  }
                  return s;
                },
                shared: true
              };
              newOptions.plotOptions = _.merge(newOptions.plotOptions, {
                series: {
                  marker: {
                    enabled: false
                  },
                  fillOpacity: 0.1
                }
              });
              if (_.isArray(scope.options)) {
                newOptions.xAxis = _.merge(newOptions.xAxis, {crosshair: true, events: {setExtremes: syncExtremes}});
              }
            } else if (scope.type && scope.type === 'solidgauge') {
              newOptions = _.merge(newOptions, {
                pane: {
                  background: {
                    innerRadius: '80%',
                    outerRadius: '100%'
                  }
                },

                tooltip: {
                  enabled: false
                },

                yAxis: {
                  showFirstLabel: false,
                  showLastLabel: false,
                  min: 0,
                  max: 100,
                  stops: [
                    [0.1, '#55BF3B'], // green
                    [0.5, '#DDDF0D'], // yellow
                    [0.9, '#DF5353'] // red
                  ],
                  minorTickInterval: null,
                  tickAmount: 2
                },

                plotOptions: {
                  solidgauge: {
                    innerRadius: '80%',
                    outerRadius: '100%',
                    dataLabels: {
                      y: 30,
                      borderWidth: 0,
                      useHTML: true
                    }
                  }
                },
                series: [{
                  dataLabels: {
                    format: '
' +
                    '{y}%
' +
                    '' + newOptions.series[0].name + '' +
                    '
'
                  }
                }]
              });
            } else if (scope.type && scope.type === 'column') {
              if (scope.stacked) {
                newOptions.plotOptions = {
                  column: {
                    stacking: 'normal'
                  }
                };
              }
            }
            Highcharts.chart(element, newOptions);
          }
        }
      }
    };
  }
}

export default ChartDirective;
<|endoftext|>


<commit_before>"use strict";
const root = require('./helpers.js').root
const ip = require('ip');

exports.HOST = ip.address();
exports.DEV_PORT = 3000;
exports.E2E_PORT = 4201;
exports.PROD_PORT = 8088;
exports.UNIVERSAL_PORT = 8000;

exports.SHOW_WEBPACK_BUNDLE_ANALYZER = false;

/**
 * These constants set whether or not you will use proxy for Webpack DevServer
 * For advanced configuration details, go to:
 * https://webpack.github.io/docs/webpack-dev-server.html#proxy
 */
exports.USE_DEV_SERVER_PROXY = false;
exports.DEV_SERVER_PROXY_CONFIG = {
  '**': 'http://localhost:8089'
}

/**
 * These constants set the source maps that will be used on build.
 * For info on source map options, go to:
 * https://webpack.github.io/docs/configuration.html#devtool
 */
exports.DEV_SOURCE_MAPS = 'eval';
exports.PROD_SOURCE_MAPS = 'source-map';

/**
 * Set watch options for Dev Server. For better HMR performance, you can
 * try setting poll to 1000 or as low as 300 and set aggregateTimeout to as low as 0.
 * These settings will effect CPU usage, so optimal setting will depend on your dev environment.
 * https://github.com/webpack/docs/wiki/webpack-dev-middleware#watchoptionsaggregatetimeout
 */
exports.DEV_SERVER_WATCH_OPTIONS = {
  poll: undefined,
  aggregateTimeout: 300,
  ignored: /node_modules/
}

/**
 * specifies which @ngrx dev tools will be available when you build and load
 * your app in dev mode. Options are: monitor | logger | both | none
 */
exports.STORE_DEV_TOOLS = 'monitor'

exports.EXCLUDE_SOURCE_MAPS = [
  // these packages have problems with their sourcemaps
  root('node_modules/@angular'),
  root('node_modules/rxjs'),
  root('node_modules/e2e4')
]

exports.MY_COPY_FOLDERS = [
  // use this for folders you want to be copied in to Client dist
  // src/assets and index.html are already copied by default.
  // format is { from: 'folder_name', to: 'folder_name' }
  { from: '.gitignore' },
  { from: 'src/favicon.ico' },
  { from: 'node_modules/normalize.css/normalize.css' },
  { from: 'node_modules/bootstrap/dist/css/bootstrap.min.css' },
  { from: 'node_modules/alertify/themes/alertify.core.css' },
  { from: 'node_modules/alertify/themes/alertify.bootstrap.css' },
  { from: 'node_modules/alertify/lib/alertify.min.js' },
  { from: 'node_modules/prismjs/themes/prism.css' }
]

exports.MY_POLYFILL_DLLS = [
  // list polyfills that you want to be included in your dlls files
  // this will speed up initial dev server build and incremental builds.
  // Be sure to run `npm run build:dll` if you make changes to this array.
]

exports.MY_VENDOR_DLLS = [
  'e2e4',
  'right-angled',
  'angulartics2',
  'prismjs',
  'clipboard'
  // list vendors that you want to be included in your dlls files
  // this will speed up initial dev server build and incremental builds.
  // Be sure to run `npm run build:dll` if you make changes to this array.
]

exports.MY_CLIENT_PLUGINS = [
  // use this to import your own webpack config Client plugins.
]

exports.MY_CLIENT_PRODUCTION_PLUGINS = [
  // use this to import your own webpack config plugins for production use.
]

exports.MY_CLIENT_RULES = [
  // use this to import your own rules for Client webpack config.
]

exports.MY_SERVER_RULES = [
  // use this to import your own rules for Universal Server webpack config.
]

exports.MY_TEST_RULES = [
  // use this to import your own rules for Test webpack config.
]

exports.MY_TEST_PLUGINS = [
  // use this to import your own Test webpack config plugins.
]

exports.MY_SERVER_INCLUDE_CLIENT_PACKAGES = [
  // include these client packages so we can transform their source with webpack loaders
]<commit_msg>remove right-angled from dlls<commit_after>"use strict";
const root = require('./helpers.js').root
const ip = require('ip');

exports.HOST = ip.address();
exports.DEV_PORT = 3000;
exports.E2E_PORT = 4201;
exports.PROD_PORT = 8088;
exports.UNIVERSAL_PORT = 8000;

exports.SHOW_WEBPACK_BUNDLE_ANALYZER = false;

/**
 * These constants set whether or not you will use proxy for Webpack DevServer
 * For advanced configuration details, go to:
 * https://webpack.github.io/docs/webpack-dev-server.html#proxy
 */
exports.USE_DEV_SERVER_PROXY = false;
exports.DEV_SERVER_PROXY_CONFIG = {
  '**': 'http://localhost:8089'
}

/**
 * These constants set the source maps that will be used on build.
 * For info on source map options, go to:
 * https://webpack.github.io/docs/configuration.html#devtool
 */
exports.DEV_SOURCE_MAPS = 'eval';
exports.PROD_SOURCE_MAPS = 'source-map';

/**
 * Set watch options for Dev Server. For better HMR performance, you can
 * try setting poll to 1000 or as low as 300 and set aggregateTimeout to as low as 0.
 * These settings will effect CPU usage, so optimal setting will depend on your dev environment.
 * https://github.com/webpack/docs/wiki/webpack-dev-middleware#watchoptionsaggregatetimeout
 */
exports.DEV_SERVER_WATCH_OPTIONS = {
  poll: undefined,
  aggregateTimeout: 300,
  ignored: /node_modules/
}

/**
 * specifies which @ngrx dev tools will be available when you build and load
 * your app in dev mode. Options are: monitor | logger | both | none
 */
exports.STORE_DEV_TOOLS = 'monitor'

exports.EXCLUDE_SOURCE_MAPS = [
  // these packages have problems with their sourcemaps
  root('node_modules/@angular'),
  root('node_modules/rxjs'),
  root('node_modules/e2e4')
]

exports.MY_COPY_FOLDERS = [
  // use this for folders you want to be copied in to Client dist
  // src/assets and index.html are already copied by default.
  // format is { from: 'folder_name', to: 'folder_name' }
  { from: '.gitignore' },
  { from: 'src/favicon.ico' },
  { from: 'node_modules/normalize.css/normalize.css' },
  { from: 'node_modules/bootstrap/dist/css/bootstrap.min.css' },
  { from: 'node_modules/alertify/themes/alertify.core.css' },
  { from: 'node_modules/alertify/themes/alertify.bootstrap.css' },
  { from: 'node_modules/alertify/lib/alertify.min.js' },
  { from: 'node_modules/prismjs/themes/prism.css' }
]

exports.MY_POLYFILL_DLLS = [
  // list polyfills that you want to be included in your dlls files
  // this will speed up initial dev server build and incremental builds.
  // Be sure to run `npm run build:dll` if you make changes to this array.
]

exports.MY_VENDOR_DLLS = [
  'angulartics2',
  'prismjs',
  'clipboard'
  // list vendors that you want to be included in your dlls files
  // this will speed up initial dev server build and incremental builds.
  // Be sure to run `npm run build:dll` if you make changes to this array.
]

exports.MY_CLIENT_PLUGINS = [
  // use this to import your own webpack config Client plugins.
]

exports.MY_CLIENT_PRODUCTION_PLUGINS = [
  // use this to import your own webpack config plugins for production use.
]

exports.MY_CLIENT_RULES = [
  // use this to import your own rules for Client webpack config.
]

exports.MY_SERVER_RULES = [
  // use this to import your own rules for Universal Server webpack config.
]

exports.MY_TEST_RULES = [
  // use this to import your own rules for Test webpack config.
]

exports.MY_TEST_PLUGINS = [
  // use this to import your own Test webpack config plugins.
]

exports.MY_SERVER_INCLUDE_CLIENT_PACKAGES = [
  // include these client packages so we can transform their source with webpack loaders
]<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.detail',
  name: 'SectionedDetailPropertyView',
  extends: 'foam.u2.View',

  documentation: `
    View for one property of a SectionedDetailView.
  `,

  css: `
    ^ m3 {
      font-size: 16px;
      font-weight: bold;
    }

    ^validation-container {
      margin-top: 6px;
    }

    ^helper-icon {
      padding-left: 12px;
      width: 20px;
      height: 20px;
    }

    ^tooltip {
      align-self: center;
      position: relative;
    }

    ^tooltip-container {
      z-index: -1;
      display: none;
      width: 80%;
      height: auto;
      line-height: 1.5;
      margin-right: 3px;
    }

    ^helper-text {
      background-color: rgba(0, 0, 0, 0.8);
      color: #fff;
      border-radius: 5px;
      border-top-right-radius: 0px;
      direction: ltr;
      padding: 2px;
      text-align: center;
    }

    ^arrow-right {
      width: 0;
      height: 0;
      border-top: 10px solid transparent;
      border-bottom: 10px solid transparent;
      border-left:10px solid rgba(0, 0, 0, 0.8);
    }

    ^tooltip:hover .foam-u2-detail-SectionedDetailPropertyView-tooltip-container{
      position: absolute;
      display: flex;
      justify-content: flex-end;

      top: 0;
      right: 25px;
      width: 380px;
      z-index: 10;
    }

    /* Necessary to style the border radius. This should probably be in Select itself. */
    ^ .foam-u2-tag-Select {
      width: 100%;
      box-shadow: none;
      background: #ffffff url('images/dropdown-icon.svg') no-repeat 99% 50%;
      -webkit-appearance: none;
      cursor: pointer;
    }

    ^flex {
      display: flex;
    }

    ^error .foam-u2-tag-TextArea,
    ^error .foam-u2-tag-Select,
    ^error .foam-u2-TextField,
    ^error .foam-u2-IntView,
    ^error .foam-u2-FloatView,
    ^error .foam-u2-DateView,
    ^error .foam-u2-view-date-DateTimePicker .date-display-box,
    ^error .foam-u2-view-RichChoiceView-selection-view,
    ^error .foam-u2-view-RichChoiceView-clear-btn
    {
      border-color: /*%DESTRUCTIVE3%*/ #d9170e !important;
    }

    /*
      !IMPORTANT!
      For the following inputs below, we are planning
      encode these changes in the actual foam files
    */

    ^ .foam-u2-TextField,
    ^ .foam-u2-tag-Select,
    ^ .foam-u2-tag-TextArea,
    ^ .foam-u2-IntView {
      width: 100%;
    }

    ^ .foam-u2-view-date-DateTimePicker {
      cursor: pointer;
    }

    ^ .foam-u2-view-RichChoiceView {
      display: flex;
    }

    ^ .foam-u2-view-RichChoiceView-chevron {
      content: '▾';
      padding-left: 0px;
      font-size: 16px;
      color: #8D9090;
    }

    ^ .foam-u2-view-RichChoiceView-selection-view {
      width: 100%;
      border-radius: 3px;
      background-color: #ffffff;
      box-sizing: border-box;
      -webkit-appearance: none;
      cursor: pointer;
      font-size: 14px;
    }

    ^ .foam-u2-view-RichChoiceView .search {
      padding: 8px 16px;
      font-size: 14px;
      border-bottom: 1px solid #f4f4f9;
    }

    ^ .foam-u2-detail-SectionedDetailPropertyView .property-filter {
      font-size: 14px;
      padding-left: 16px;
    }

    ^ .foam-u2-view-RichChoiceView .search input {
      border-bottom: none;
    }

    ^ .foam-u2-view-RichChoiceView .search img {
      top: 8px;
    }

    ^ .foam-u2-view-RichChoiceView-heading {
      border-bottom: 1px solid #f4f4f9;
      line-height: 24px;
      font-size: 14px;
      color: #333;
      font-weight: 900;
      padding: 6px 16px;
    }

    ^ .foam-u2-view-RichChoiceView-container {
      z-index: 1000;
    }

    ^ .DefaultRowView-row {
      background: white;
      padding: 8px 16px;
      font-size: 12px;
      color: #424242;
    }

    ^ .DefaultRowView-row:hover {
      background: #f4f4f9;
      cursor: pointer;
    }

    ^ .foam-u2-CheckBox-label {
      word-break: break-word;
      white-space: normal;
      margin-top: 6px;
    }

    ^ .foam-u2-view-RadioView .foam-u2-view-RadioView {
      margin-bottom:16px;
      display: flex;
      align-items: center;
      font-size: 16px;
      margin-right: auto;
    }

    ^ .foam-u2-view-RadioView label {
      margin-left: 12px;
    }

    ^ .foam-u2-layout-Cols {
      padding-bottom: 4px;
      display: flex;
      align-items: center;
    }
  `,

  requires: [
    'foam.core.ConstantSlot',
    'foam.core.ProxySlot',
    'foam.u2.layout.Cols',
    'foam.u2.layout.Rows',
    'foam.u2.ControllerMode',
    'foam.u2.DisplayMode'
  ],

  properties: [
    'prop'
  ],

  methods: [
    function initE() {
      var self = this;
      this.SUPER();

      this.onDetach(this.mode$.follow(self.prop.createVisibilityFor(self.data$, self.controllerMode$)));

      this
        .addClass(this.myClass())
        .addClass(`sectioned-detail-property-${this.prop.name}`)
        .add(this.slot(function(mode, prop, prop$label) {

          var isCheckBox = false;
          if ( typeof prop.view === "function" ) {
            var view = prop.view(null, this);
            isCheckBox = view.class === 'foam.u2.CheckBox' || ( view.cls_ && view.cls_.id === 'foam.u2.CheckBox' );
          }
          else {
            isCheckBox = prop.view.class === 'foam.u2.CheckBox';
          }

          var errorSlot = prop.validateObj && prop.validationTextVisible ?
            this.data.slot(prop.validateObj) :
            foam.core.ConstantSlot.create({ value: null });

          return self.E()
            .start(self.Rows)
              .callIf(prop$label && ! isCheckBox, function() {
                this.start('m3')
                  .add(prop$label)
                  .style({ 'line-height': '2' })
                .end();
              })
              .start()
                .style({ 'position': 'relative', 'display': 'inline-flex', 'width': '100%' })
                .start()
                  .style({ 'flex-grow': 1, 'max-width': '100%' })
                  .enableClass(self.myClass('flex'), isCheckBox)
                  .tag(prop, { mode$: self.mode$ })
                  .callIf(prop.validationStyleEnabled, function() {
                    this.enableClass(self.myClass('error'), errorSlot);
                  })
                .end()
                .callIf(prop.help, function() {
                  this.start()
                    .addClass(self.myClass('tooltip'))
                    .start({class: 'foam.u2.tag.Image', data: 'images/question-icon.svg'})
                      .addClass(self.myClass('helper-icon'))
                    .end()

                    .start()
                      .addClass(self.myClass('tooltip-container'))
                      .start()
                        .addClass(self.myClass('helper-text'))
                        .start('p').style({ 'padding': '3px' })
                          .add(prop.help)
                        .end()
                      .end()
                      .start()
                        .addClass(self.myClass('arrow-right'))
                      .end()
                    .end()
                  .end();
                })
              .end()
              .callIf(prop.validationTextVisible && ( mode === self.DisplayMode.RW || mode === self.DisplayMode.DISABLED ), function() {
                this
                  .start()
                    .style({ 'align-items': 'center' })
                    .start(self.Cols)
                      .addClass(self.myClass('validation-container'))
                      .show(errorSlot)
                      .start({
                        class: 'foam.u2.tag.Image',
                        data: 'images/inline-error-icon.svg',
                        displayHeight: '16px',
                        displayWidth: '16px'
                      })
                        .style({
                          'justify-content': 'flex-start',
                          'margin': '0 8px 0 0'
                        })
                      .end()
                      .start()
                        .style({ 'flex-grow': 1 })
                        .add(errorSlot.map((s) => {
                          return self.E().add(s);
                        }))
                      .end()
                    .end()
                  .end();
              })
            .end();
        }));
    }
  ]
});
<commit_msg>refactor<commit_after>/**
 * @license
 * Copyright 2019 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.u2.detail',
  name: 'SectionedDetailPropertyView',
  extends: 'foam.u2.View',

  documentation: `
    View for one property of a SectionedDetailView.
  `,

  css: `
    ^ m3 {
      font-size: 16px;
      font-weight: bold;
    }

    ^validation-container {
      margin-top: 6px;
    }

    ^helper-icon {
      padding-left: 12px;
      width: 20px;
      height: 20px;
    }

    ^tooltip {
      align-self: center;
      position: relative;
    }

    ^tooltip-container {
      z-index: -1;
      display: none;
      width: 80%;
      height: auto;
      line-height: 1.5;
      margin-right: 3px;
    }

    ^helper-text {
      background-color: rgba(0, 0, 0, 0.8);
      color: #fff;
      border-radius: 5px;
      border-top-right-radius: 0px;
      direction: ltr;
      padding: 2px;
      text-align: center;
    }

    ^arrow-right {
      width: 0;
      height: 0;
      border-top: 10px solid transparent;
      border-bottom: 10px solid transparent;
      border-left:10px solid rgba(0, 0, 0, 0.8);
    }

    ^tooltip:hover .foam-u2-detail-SectionedDetailPropertyView-tooltip-container{
      position: absolute;
      display: flex;
      justify-content: flex-end;

      top: 0;
      right: 25px;
      width: 380px;
      z-index: 10;
    }

    /* Necessary to style the border radius. This should probably be in Select itself. */
    ^ .foam-u2-tag-Select {
      width: 100%;
      box-shadow: none;
      background: #ffffff url('images/dropdown-icon.svg') no-repeat 99% 50%;
      -webkit-appearance: none;
      cursor: pointer;
    }

    ^flex {
      display: flex;
    }

    ^error .foam-u2-tag-TextArea,
    ^error .foam-u2-tag-Select,
    ^error .foam-u2-TextField,
    ^error .foam-u2-IntView,
    ^error .foam-u2-FloatView,
    ^error .foam-u2-DateView,
    ^error .foam-u2-view-date-DateTimePicker .date-display-box,
    ^error .foam-u2-view-RichChoiceView-selection-view,
    ^error .foam-u2-view-RichChoiceView-clear-btn
    {
      border-color: /*%DESTRUCTIVE3%*/ #d9170e !important;
    }

    /*
      !IMPORTANT!
      For the following inputs below, we are planning
      encode these changes in the actual foam files
    */

    ^ .foam-u2-TextField,
    ^ .foam-u2-tag-Select,
    ^ .foam-u2-tag-TextArea,
    ^ .foam-u2-IntView {
      width: 100%;
    }

    ^ .foam-u2-view-date-DateTimePicker {
      cursor: pointer;
    }

    ^ .foam-u2-view-RichChoiceView {
      display: flex;
    }

    ^ .foam-u2-view-RichChoiceView-chevron {
      content: '▾';
      padding-left: 0px;
      font-size: 16px;
      color: #8D9090;
    }

    ^ .foam-u2-view-RichChoiceView-selection-view {
      width: 100%;
      border-radius: 3px;
      background-color: #ffffff;
      box-sizing: border-box;
      -webkit-appearance: none;
      cursor: pointer;
      font-size: 14px;
    }

    ^ .foam-u2-view-RichChoiceView .search {
      padding: 8px 16px;
      font-size: 14px;
      border-bottom: 1px solid #f4f4f9;
    }

    ^ .foam-u2-detail-SectionedDetailPropertyView .property-filter {
      font-size: 14px;
      padding-left: 16px;
    }

    ^ .foam-u2-view-RichChoiceView .search input {
      border-bottom: none;
    }

    ^ .foam-u2-view-RichChoiceView .search img {
      top: 8px;
    }

    ^ .foam-u2-view-RichChoiceView-heading {
      border-bottom: 1px solid #f4f4f9;
      line-height: 24px;
      font-size: 14px;
      color: #333;
      font-weight: 900;
      padding: 6px 16px;
    }

    ^ .foam-u2-view-RichChoiceView-container {
      z-index: 1000;
    }

    ^ .DefaultRowView-row {
      background: white;
      padding: 8px 16px;
      font-size: 12px;
      color: #424242;
    }

    ^ .DefaultRowView-row:hover {
      background: #f4f4f9;
      cursor: pointer;
    }

    ^ .foam-u2-CheckBox-label {
      word-break: break-word;
      white-space: normal;
      margin-top: 6px;
    }

    ^ .foam-u2-view-RadioView .foam-u2-view-RadioView {
      margin-bottom:16px;
      display: flex;
      align-items: center;
      font-size: 16px;
      margin-right: auto;
    }

    ^ .foam-u2-view-RadioView label {
      margin-left: 12px;
    }

    ^ .foam-u2-layout-Cols {
      padding-bottom: 4px;
      display: flex;
      align-items: center;
    }
  `,

  requires: [
    'foam.core.ConstantSlot',
    'foam.core.ProxySlot',
    'foam.u2.layout.Cols',
    'foam.u2.layout.Rows',
    'foam.u2.ControllerMode',
    'foam.u2.DisplayMode'
  ],

  properties: [
    'prop'
  ],

  methods: [
    function initE() {
      var self = this;
      this.SUPER();

      this.onDetach(this.mode$.follow(self.prop.createVisibilityFor(self.data$, self.controllerMode$)));

      this
        .addClass(this.myClass())
        .addClass(`sectioned-detail-property-${this.prop.name}`)
        .add(this.slot(function(mode, prop, prop$label) {

          var isCheckBox = false;
          if ( foam.Function.isInstance(prop.view) ) {
            var view = prop.view(null, this);
            isCheckBox = view.class === 'foam.u2.CheckBox' || ( view.cls_ && view.cls_.id === 'foam.u2.CheckBox' );
          }
          else {
            isCheckBox = prop.view.class === 'foam.u2.CheckBox';
          }

          var errorSlot = prop.validateObj && prop.validationTextVisible ?
            this.data.slot(prop.validateObj) :
            foam.core.ConstantSlot.create({ value: null });

          return self.E()
            .start(self.Rows)
              .callIf(prop$label && ! isCheckBox, function() {
                this.start('m3')
                  .add(prop$label)
                  .style({ 'line-height': '2' })
                .end();
              })
              .start()
                .style({ 'position': 'relative', 'display': 'inline-flex', 'width': '100%' })
                .start()
                  .style({ 'flex-grow': 1, 'max-width': '100%' })
                  .enableClass(self.myClass('flex'), isCheckBox)
                  .tag(prop, { mode$: self.mode$ })
                  .callIf(prop.validationStyleEnabled, function() {
                    this.enableClass(self.myClass('error'), errorSlot);
                  })
                .end()
                .callIf(prop.help, function() {
                  this.start()
                    .addClass(self.myClass('tooltip'))
                    .start({class: 'foam.u2.tag.Image', data: 'images/question-icon.svg'})
                      .addClass(self.myClass('helper-icon'))
                    .end()

                    .start()
                      .addClass(self.myClass('tooltip-container'))
                      .start()
                        .addClass(self.myClass('helper-text'))
                        .start('p').style({ 'padding': '3px' })
                          .add(prop.help)
                        .end()
                      .end()
                      .start()
                        .addClass(self.myClass('arrow-right'))
                      .end()
                    .end()
                  .end();
                })
              .end()
              .callIf(prop.validationTextVisible && ( mode === self.DisplayMode.RW || mode === self.DisplayMode.DISABLED ), function() {
                this
                  .start()
                    .style({ 'align-items': 'center' })
                    .start(self.Cols)
                      .addClass(self.myClass('validation-container'))
                      .show(errorSlot)
                      .start({
                        class: 'foam.u2.tag.Image',
                        data: 'images/inline-error-icon.svg',
                        displayHeight: '16px',
                        displayWidth: '16px'
                      })
                        .style({
                          'justify-content': 'flex-start',
                          'margin': '0 8px 0 0'
                        })
                      .end()
                      .start()
                        .style({ 'flex-grow': 1 })
                        .add(errorSlot.map((s) => {
                          return self.E().add(s);
                        }))
                      .end()
                    .end()
                  .end();
              })
            .end();
        }));
    }
  ]
});
<|endoftext|>


<commit_before>var mongo = require('mongodb');
var url = require('url');
var Collection = require('./collection');
var Grid = require('./grid');
var MetaCache = require('./metacache');
var Promise = require('./promise');
var Store = require('./store');

module.exports = Connection;

function Connection(options) {
    if (typeof options === 'string') {
        var uri = url.parse(options);
        this.options = {};
        this.options.host = uri.hostname;
        this.options.port = parseInt(uri.port, 10);
        this.options.db = uri.pathname && uri.pathname.replace(/\//g, '');

        if (uri.auth) {
            var auth = uri.auth.split(':');
            this.options.user = auth[0];
            this.options.pass = auth[1];
        }
    } else {
        this.options = options || {};
        this.options.host || (this.options.host = 'localhost');
        this.options.port || (this.options.port = 27017);
    }

    if (this.options.db === undefined) {
        throw new Error('No `db` specified');
    }

    this.db = new Promise();
    this.collections = {};
    this.grids = {};
};

Connection.prototype.collection = function(name) {
    this.collections[name] || (this.collections[name] = new Collection(name, this.db));
    return this.collections[name];
};

Connection.prototype.grid = function(name) {
    this.grids[name] || (this.grids[name] = new Grid(name, this.db));
    return this.grids[name];
};

Connection.prototype.store = function(name) {
    var entities = this.grid(name);
    var cache = this.grid(name + '.cache');
    var metacache = new MetaCache(this.collection(name + '.metacache'));

    return new Store(entities, cache, metacache);
};

Connection.prototype.open = function(callback) {
    var self = this;
    var server = new mongo.Server(this.options.host, this.options.port, {});
    var db = new mongo.Db(this.options.db, server);

    db.open(function(err, db) {
        var opened = function() {
            self.db.resolve(err, db);
            if (callback) callback(err, db);
        };

        if (self.options.user && self.options.pass) {
            db.authenticate(self.options.user, self.options.pass, opened)
        } else {
            opened();
        }
    });
};<commit_msg>Allow db url to be passed as option<commit_after>var mongo = require('mongodb');
var url = require('url');
var Collection = require('./collection');
var Grid = require('./grid');
var MetaCache = require('./metacache');
var Promise = require('./promise');
var Store = require('./store');

module.exports = Connection;

function Connection(options) {
    if (typeof options === 'string') {
        options = { url: options };
    }

    if (options.url) {
        var uri = url.parse(options.url);
        this.options = {};
        this.options.host = uri.hostname;
        this.options.port = parseInt(uri.port, 10);
        this.options.db = uri.pathname && uri.pathname.replace(/\//g, '');

        if (uri.auth) {
            var auth = uri.auth.split(':');
            this.options.user = auth[0];
            this.options.pass = auth[1];
        }
    } else {
        this.options = options || {};
        this.options.host || (this.options.host = 'localhost');
        this.options.port || (this.options.port = 27017);
    }

    if (this.options.db === undefined) {
        throw new Error('No `db` specified');
    }

    this.db = new Promise();
    this.collections = {};
    this.grids = {};
};

Connection.prototype.collection = function(name) {
    this.collections[name] || (this.collections[name] = new Collection(name, this.db));
    return this.collections[name];
};

Connection.prototype.grid = function(name) {
    this.grids[name] || (this.grids[name] = new Grid(name, this.db));
    return this.grids[name];
};

Connection.prototype.store = function(name) {
    var entities = this.grid(name);
    var cache = this.grid(name + '.cache');
    var metacache = new MetaCache(this.collection(name + '.metacache'));

    return new Store(entities, cache, metacache);
};

Connection.prototype.open = function(callback) {
    var self = this;
    var server = new mongo.Server(this.options.host, this.options.port, {});
    var db = new mongo.Db(this.options.db, server);

    db.open(function(err, db) {
        var opened = function() {
            self.db.resolve(err, db);
            if (callback) callback(err, db);
        };

        if (self.options.user && self.options.pass) {
            db.authenticate(self.options.user, self.options.pass, opened)
        } else {
            opened();
        }
    });
};<|endoftext|>


<commit_before>var h = require('hyperscript')
var pull = require('pull-stream')
var u = require('./util')

exports.createStream = function createStream (stream, render) {
  var div = h('div.content')

  pull(
    stream,
    pull.drain(function (data) {
      var el = render(data)
      if('string' === typeof el) el = document.createTextNode(el)
      if(el) {
        if(div.children.length)
          div.appendChild(h('hr'))
        div.appendChild(el)
      }

    })
  )

  return div
}

exports.createRenderers = function (renderers, sbot) {
  return function (data) {
    return u.first(renderers, function (fn) {
      return fn(data, sbot)
    })
  }
}
<commit_msg>use pull-scroll to get infinite scrolling<commit_after>var h = require('hyperscript')
var pull = require('pull-stream')
var u = require('./util')
var Scroller = require('pull-scroll')

exports.createStream = function createStream (stream, render) {
  var div = h('div.column', {style: {'overflow-y': 'auto'}})

  pull(
    stream,
    Scroller(div, div, render, false, false)
  )

  return div
}

exports.createRenderers = function (renderers, sbot) {
  return function (data) {
    return u.first(renderers, function (fn) {
      return fn(data, sbot)
    })
  }
}

<|endoftext|>


<commit_before>import {
  cookingStatus,
  preparationTime,
  quantities,
  addSecretIngredient,
  scaleRecipe,
} from './lasagna-master';

const DIFFERENCE_PRECISION_IN_DIGITS = 6;

describe('cookingStatus', () => {
  test('recognizes that there is time left on the timer', () => {
    const expected = 'Not done, please wait.';
    expect(cookingStatus(1)).toBe(expected);
    expect(cookingStatus(42)).toBe(expected);
    expect(cookingStatus(8.5)).toBe(expected);
    expect(cookingStatus(0.1)).toBe(expected);
  });

  test('recognizes when there is no time left on the timer', () => {
    expect(cookingStatus(0)).toBe('Lasagna is done.');
  });

  test('returns a special status when no timer value was passed', () => {
    const expected = 'You forgot to set the timer.';
    expect(cookingStatus()).toBe(expected);
    expect(cookingStatus(undefined)).toBe(expected);
  });
});

describe('preparationTime', () => {
  test('applies the custom average time per layer', () => {
    const manyLayers = [
      'sauce',
      'noodles',
      'béchamel',
      'meat',
      'mozzarella',
      'noodles',
      'ricotta',
      'eggplant',
      'béchamel',
      'noodles',
      'sauce',
      'mozzarella',
    ];
    expect(preparationTime(manyLayers, 1)).toBe(12);

    const fewLayers = ['sauce', 'noodles'];
    expect(preparationTime(fewLayers, 3.5)).toBe(7);
  });

  test('uses the default if no custom time was passed', () => {
    const manyLayers = [
      'sauce',
      'noodles',
      'béchamel',
      'meat',
      'mozzarella',
      'noodles',
      'ricotta',
      'eggplant',
      'béchamel',
      'noodles',
      'sauce',
      'mozzarella',
    ];
    expect(preparationTime(manyLayers)).toBe(24);

    const fewLayers = ['sauce', 'noodles'];
    expect(preparationTime(fewLayers)).toBe(4);
  });

  test('works with an empty layers array', () => {
    expect(preparationTime([])).toBe(0);
  });
});

describe('quantities', () => {
  test('calculates the amounts of noodles and sauce correctly', () => {
    const fewLayers = ['noodles', 'sauce', 'noodles'];
    expectObjectsToBeEqual(quantities(fewLayers), { noodles: 100, sauce: 0.2 });

    const manyLayers = [
      'sauce',
      'noodles',
      'béchamel',
      'meat',
      'mozzarella',
      'noodles',
      'ricotta',
      'eggplant',
      'béchamel',
      'noodles',
      'sauce',
      'mozzarella',
    ];
    expectObjectsToBeEqual(quantities(manyLayers), {
      noodles: 150,
      sauce: 0.4,
    });
  });

  test('works if there are no noodles or no sauce found in the layers', () => {
    const noNoodles = ['sauce', 'béchamel', 'sauce', 'meat', 'sauce'];
    expectObjectsToBeEqual(quantities(noNoodles), { noodles: 0, sauce: 0.6 });

    const noSauce = ['eggplant', 'béchamel', 'noodles', 'béchamel'];
    expectObjectsToBeEqual(quantities(noSauce), { noodles: 50, sauce: 0 });
  });

  test('works with an empty layers array', () => {
    expect(quantities([])).toEqual({ noodles: 0, sauce: 0 });
  });
});

describe('addSecretIngredient', () => {
  test('adds the secret ingredient to the second array', () => {
    const friendsList = ['sauce', 'noodles', 'béchamel', 'marjoram'];
    const myList = ['sauce', 'noodles', 'meat', 'tomatoes'];
    addSecretIngredient(friendsList, myList);

    const expected = ['sauce', 'noodles', 'meat', 'tomatoes', 'marjoram'];
    expect(myList).toEqual(expected);
  });

  test('does not modify the first array', () => {
    const createFriendsList = () => [
      'noodles',
      'tomatoes',
      'sauce',
      'meat',
      'mozzarella',
      'eggplant',
      'ricotta',
      'parmesan',
    ];

    const friendsList = createFriendsList();
    const myList = ['ricotta', 'béchamel', 'sauce', 'noodles', 'meat'];
    addSecretIngredient(friendsList, myList);

    expect(friendsList).toEqual(createFriendsList());
  });

  test('does not return anything', () => {
    const friendsList = [
      'sauce',
      'noodles',
      'béchamel',
      'mozzarella',
      'mustard',
    ];
    const myList = ['sauce', 'noodles', 'tomatoes'];
    expect(addSecretIngredient(friendsList, myList)).toBeUndefined();
  });
});

describe('scaleRecipe', () => {
  test('scales up correctly', () => {
    const recipe1 = {
      sauce: 0.5,
      noodles: 250,
      meat: 150,
      tomatoes: 3,
      onion: 0.5,
    };

    const expected1 = {
      sauce: 1.5,
      noodles: 750,
      meat: 450,
      tomatoes: 9,
      onion: 1.5,
    };

    expectObjectsToBeEqual(scaleRecipe(recipe1, 6), expected1);

    // prettier-ignore
    const recipe2 = {
      'sauce': 0.6,
      'noodles': 300,
      'carrots': 1,
      'mozzarella': 0.5,
      'ricotta': 50,
      'béchamel': 0.1,
      'tofu': 100,
    };

    // prettier-ignore
    const expected2 = {
      'sauce': 0.9,
      'noodles': 450,
      'carrots': 1.5,
      'mozzarella': 0.75,
      'ricotta': 75,
      'béchamel': 0.15,
      'tofu': 150,
    };

    expectObjectsToBeEqual(scaleRecipe(recipe2, 3), expected2);
  });

  test('scales down correctly', () => {
    const recipe = {
      sauce: 0.5,
      noodles: 250,
      meat: 150,
      tomatoes: 3,
      onion: 0.5,
    };

    const expected = {
      sauce: 0.25,
      noodles: 125,
      meat: 75,
      tomatoes: 1.5,
      onion: 0.25,
    };
    expectObjectsToBeEqual(scaleRecipe(recipe, 1), expected);
  });

  test('works for an empty recipe', () => {
    expect(scaleRecipe({})).toEqual({});
  });
});

/**
 * Jest does not support comparing objects that contain floating point number values.
 * https://github.com/facebook/jest/issues/3654
 * This helper functions applies "toBeCloseTo" to compare object values.
 */
function expectObjectsToBeEqual(actualObj, expectedObj) {
  for (const key in expectedObj) {
    expect(actualObj[key]).toBeCloseTo(
      expectedObj[key],
      DIFFERENCE_PRECISION_IN_DIGITS
    );
  }
  expect(Object.keys(actualObj).length).toBe(Object.keys(expectedObj).length);
}
<commit_msg>Check that original recipe is not modified (#1499)<commit_after>import {
  cookingStatus,
  preparationTime,
  quantities,
  addSecretIngredient,
  scaleRecipe,
} from './lasagna-master';

const DIFFERENCE_PRECISION_IN_DIGITS = 6;

describe('cookingStatus', () => {
  test('recognizes that there is time left on the timer', () => {
    const expected = 'Not done, please wait.';
    expect(cookingStatus(1)).toBe(expected);
    expect(cookingStatus(42)).toBe(expected);
    expect(cookingStatus(8.5)).toBe(expected);
    expect(cookingStatus(0.1)).toBe(expected);
  });

  test('recognizes when there is no time left on the timer', () => {
    expect(cookingStatus(0)).toBe('Lasagna is done.');
  });

  test('returns a special status when no timer value was passed', () => {
    const expected = 'You forgot to set the timer.';
    expect(cookingStatus()).toBe(expected);
    expect(cookingStatus(undefined)).toBe(expected);
  });
});

describe('preparationTime', () => {
  test('applies the custom average time per layer', () => {
    const manyLayers = [
      'sauce',
      'noodles',
      'béchamel',
      'meat',
      'mozzarella',
      'noodles',
      'ricotta',
      'eggplant',
      'béchamel',
      'noodles',
      'sauce',
      'mozzarella',
    ];
    expect(preparationTime(manyLayers, 1)).toBe(12);

    const fewLayers = ['sauce', 'noodles'];
    expect(preparationTime(fewLayers, 3.5)).toBe(7);
  });

  test('uses the default if no custom time was passed', () => {
    const manyLayers = [
      'sauce',
      'noodles',
      'béchamel',
      'meat',
      'mozzarella',
      'noodles',
      'ricotta',
      'eggplant',
      'béchamel',
      'noodles',
      'sauce',
      'mozzarella',
    ];
    expect(preparationTime(manyLayers)).toBe(24);

    const fewLayers = ['sauce', 'noodles'];
    expect(preparationTime(fewLayers)).toBe(4);
  });

  test('works with an empty layers array', () => {
    expect(preparationTime([])).toBe(0);
  });
});

describe('quantities', () => {
  test('calculates the amounts of noodles and sauce correctly', () => {
    const fewLayers = ['noodles', 'sauce', 'noodles'];
    expectObjectsToBeEqual(quantities(fewLayers), { noodles: 100, sauce: 0.2 });

    const manyLayers = [
      'sauce',
      'noodles',
      'béchamel',
      'meat',
      'mozzarella',
      'noodles',
      'ricotta',
      'eggplant',
      'béchamel',
      'noodles',
      'sauce',
      'mozzarella',
    ];
    expectObjectsToBeEqual(quantities(manyLayers), {
      noodles: 150,
      sauce: 0.4,
    });
  });

  test('works if there are no noodles or no sauce found in the layers', () => {
    const noNoodles = ['sauce', 'béchamel', 'sauce', 'meat', 'sauce'];
    expectObjectsToBeEqual(quantities(noNoodles), { noodles: 0, sauce: 0.6 });

    const noSauce = ['eggplant', 'béchamel', 'noodles', 'béchamel'];
    expectObjectsToBeEqual(quantities(noSauce), { noodles: 50, sauce: 0 });
  });

  test('works with an empty layers array', () => {
    expect(quantities([])).toEqual({ noodles: 0, sauce: 0 });
  });
});

describe('addSecretIngredient', () => {
  test('adds the secret ingredient to the second array', () => {
    const friendsList = ['sauce', 'noodles', 'béchamel', 'marjoram'];
    const myList = ['sauce', 'noodles', 'meat', 'tomatoes'];
    addSecretIngredient(friendsList, myList);

    const expected = ['sauce', 'noodles', 'meat', 'tomatoes', 'marjoram'];
    expect(myList).toEqual(expected);
  });

  test('does not modify the first array', () => {
    const createFriendsList = () => [
      'noodles',
      'tomatoes',
      'sauce',
      'meat',
      'mozzarella',
      'eggplant',
      'ricotta',
      'parmesan',
    ];

    const friendsList = createFriendsList();
    const myList = ['ricotta', 'béchamel', 'sauce', 'noodles', 'meat'];
    addSecretIngredient(friendsList, myList);

    expect(friendsList).toEqual(createFriendsList());
  });

  test('does not return anything', () => {
    const friendsList = [
      'sauce',
      'noodles',
      'béchamel',
      'mozzarella',
      'mustard',
    ];
    const myList = ['sauce', 'noodles', 'tomatoes'];
    expect(addSecretIngredient(friendsList, myList)).toBeUndefined();
  });
});

describe('scaleRecipe', () => {
  test('scales up correctly', () => {
    const recipe1 = {
      sauce: 0.5,
      noodles: 250,
      meat: 150,
      tomatoes: 3,
      onion: 0.5,
    };

    const expected1 = {
      sauce: 1.5,
      noodles: 750,
      meat: 450,
      tomatoes: 9,
      onion: 1.5,
    };

    expectObjectsToBeEqual(scaleRecipe(recipe1, 6), expected1);

    // prettier-ignore
    const recipe2 = {
      'sauce': 0.6,
      'noodles': 300,
      'carrots': 1,
      'mozzarella': 0.5,
      'ricotta': 50,
      'béchamel': 0.1,
      'tofu': 100,
    };

    // prettier-ignore
    const expected2 = {
      'sauce': 0.9,
      'noodles': 450,
      'carrots': 1.5,
      'mozzarella': 0.75,
      'ricotta': 75,
      'béchamel': 0.15,
      'tofu': 150,
    };

    expectObjectsToBeEqual(scaleRecipe(recipe2, 3), expected2);
  });

  test('scales down correctly', () => {
    const recipe = {
      sauce: 0.5,
      noodles: 250,
      meat: 150,
      tomatoes: 3,
      onion: 0.5,
    };

    const expected = {
      sauce: 0.25,
      noodles: 125,
      meat: 75,
      tomatoes: 1.5,
      onion: 0.25,
    };
    expectObjectsToBeEqual(scaleRecipe(recipe, 1), expected);
  });

  test('works for an empty recipe', () => {
    expect(scaleRecipe({})).toEqual({});
  });

  test('does not modify the original recipe', () => {
    const recipe = {
      sauce: 1,
      noodles: 250,
      meat: 150,
      tomatoes: 3,
      onion: 2,
    };

    const copy = { ...recipe };

    scaleRecipe(recipe, 4);
    expect(recipe).toEqual(copy);
  });
});

/**
 * Jest does not support comparing objects that contain floating point number values.
 * https://github.com/facebook/jest/issues/3654
 * This helper functions applies "toBeCloseTo" to compare object values.
 */
function expectObjectsToBeEqual(actualObj, expectedObj) {
  for (const key in expectedObj) {
    expect(actualObj[key]).toBeCloseTo(
      expectedObj[key],
      DIFFERENCE_PRECISION_IN_DIGITS
    );
  }
  expect(Object.keys(actualObj).length).toBe(Object.keys(expectedObj).length);
}
<|endoftext|>