<commit_before>import File from './file';

export default class Package extends File {
  async templateRepo(context) {
    const content = await this.originalContent(context, {
      ignoreMissing: true
    });
    const pkg = JSON.parse(content);
    if (pkg.template !== undefined && pkg.template.repository !== undefined) {
      const m = pkg.template.repository.url.match(/github.com\/(.*)\.git$/);
      return m[1];
    }

    return undefined;
  }

  async merge(context) {
    const [original, templateContent] = await Promise.all([
      this.originalContent(context, {
        ignoreMissing: true
      }),
      this.templateContent(context)
    ]);

    const originalLastChar = original[original.length - 1];

    let target =
      original === undefined || original === '' ? {} : JSON.parse(original);
    const template = JSON.parse(templateContent);
    const messages = [];
    const properties = context.properties;

    if (target.name === undefined || target.name === '') {
      const m = context.targetRepo.name.match(/^([^\/]+)\/(.*)/);
      target.name = m ? m[2] : context.targetRepo.name;
    }

    if (target.module !== undefined && !target.module.match(/\{\{module\}\}/)) {
      properties.module = target.module;
    }

    properties.main =
      target.main && !target.main.match(/\{\{main\}\}/)
        ? target.main
        : 'dist/index.js';

    const githubURL = `git+https://github.com/${properties.user}/${target.name}.git`;
    const githubURLAlternative = `git+https://github.com/${properties.user}/node-${target.name}.git`;

    let repoName = target.name;

    if (
      target.repository === undefined ||
      (target.repository.url !== githubURL &&
        target.repository.url !== githubURLAlternative)
    ) {
      target.repository = {
        type: 'git',
        url: githubURL
      };
      messages.push(`chore(package): correct github url`);
    }

    if (
      target.repository !== undefined &&
      githubURLAlternative === target.repository.url
    ) {
      repoName = `node-${target.name}`;
    }

    const bugsURL = `https://github.com/${properties.user}/${repoName}/issues`;

    if (target.bugs === undefined || target.bugs.url !== bugsURL) {
      target.bugs = {
        url: bugsURL
      };
      messages.push(`chore(package): correct bugs url`);
    }

    const homepageURL = `https://github.com/${properties.user}/${repoName}#readme`;

    if (target.homepage === undefined || target.homepage !== homepageURL) {
      target.homepage = homepageURL;
      messages.push(`chore(package): correct hompage url`);
    }

    let buildOutput;
    const extraBuilds = {};

    if (target.scripts !== undefined) {
      Object.keys(target.scripts).forEach(key => {
        const script = target.scripts[key];
        const ma = script.match(/--output=([^\s]+)/);
        if (ma) {
          buildOutput = ma[1];
        }

        const templateScript = template.scripts[key];
        if (templateScript !== undefined) {
          const mb = script.match(/&&\s*(.+)$/);
          if (mb && !templateScript.includes(mb[1])) {
            extraBuilds[key] = mb[1];
          }
        }
      });
    }

    const deepPropeties = {
      scripts: {},
      devDependencies: {},
      engines: {}
    };

    Object.keys(deepPropeties).forEach(p => {
      if (target[p] === undefined) {
        target[p] = {};
      }

      if (template[p] !== undefined) {
        Object.keys(template[p]).forEach(d => {
          if (template[p][d] === '-') {
            if (target[p][d] !== undefined) {
              messages.push(`chore(${p}): remove ${d}@${target[p][d]}`);
              delete target[p][d];
            }
          } else {
            const tp = context.expand(template[p][d]);
            if (tp !== target[p][d]) {
              messages.push(
                target[p][d] === undefined
                  ? `chore(${p}): add ${d}@${tp} from template`
                  : `chore(${p}): update ${d}@${tp} from template`
              );
              target[p][d] = tp;
            }
          }
        });
      }
    });

    Object.keys(template).forEach(p => {
      if (p !== 'template') {
        if (target[p] === undefined) {
          target[p] = template[p];
        }
      }
    });

    if (target.scripts.prepare) {
      if (buildOutput !== undefined) {
        target.scripts.prepare = target.scripts.prepare.replace(
          /--output=([^\s]+)/,
          `--output=${buildOutput}`
        );
      }
    }

    Object.keys(extraBuilds).forEach(key => {
      target.scripts[key] += ` && ${extraBuilds[key]}`;
    });

    if (target.module === '{{module}}') {
      delete target.module;
    }

    if (
      target.contributors !== undefined &&
      target.author !== undefined &&
      target.author.name !== undefined
    ) {
      const m = target.author.name.match(/(^[^<]+)<([^>]+)>/);
      if (m !== undefined) {
        const name = String(m[1]).replace(/^\s+|\s+$/g, '');
        const email = m[2];

        if (
          target.contributors.find(c => c.name === name && c.email === email)
        ) {
          delete target.author;
        }
      }
    }

    if (
      target.template === undefined ||
      target.template.repository === undefined ||
      target.template.repository.url !==
        `https://github.com/${context.templateRepo.name}.git`
    ) {
      messages.push('chore(package): set template repo');

      target.template = {
        repository: {
          url: `https://github.com/${context.templateRepo.name}.git`
        }
      };
    }

    // TODO loop over all rollup files
    const [modules1, modules2] = await Promise.all(
      ['rollup.config.js', 'tests/rollup.config.js'].map(async file => {
        const rcj = await context.files.get(file);
        if (rcj) {
          const m = await rcj.merge(context);
          return rcj.usedModules(m.content);
        }
        return new Set();
      })
    );

    Object.keys(target.devDependencies)
      .filter(m => {
        if (m.match(/rollup-plugin/)) {
          return modules1.has(m) || modules2.has(m) ? false : true;
        }

        return false;
      })
      .forEach(toBeRemoved => {
        delete target.devDependencies[toBeRemoved];
      });

    target = deleter(target, template, messages, []);

    if (target.keywords !== undefined) {
      delete target.keywords['npm-package-template'];
    }

    if (
      template.template !== undefined &&
      template.template.keywords !== undefined
    ) {
      Object.keys(template.template.keywords).forEach(r =>
        addKeyword(
          target,
          new RegExp(r),
          template.template.keywords[r],
          messages
        )
      );
    }

    removeKeyword(target, ['null', null, undefined], messages);

    if (messages.length === 0) {
      messages.push('chore: update package.json from template');
    }

    let newContent = JSON.stringify(context.expand(target), undefined, 2);
    const lastChar = newContent[newContent.length - 1];

    // keep trailing newline
    if (originalLastChar === '\n' && lastChar === '}') {
      newContent += '\n';
    }

    return {
      content: newContent,
      messages,
      path: this.path,
      changed: original !== newContent
    };
  }
}

function deleter(object, reference, messages, path) {
  if (
    typeof object === 'string' ||
    object instanceof String ||
    object === true ||
    object === false ||
    object === undefined ||
    object === null ||
    typeof object === 'number' ||
    object instanceof Number
  ) {
    return object;
  }

  Object.keys(reference).forEach(key => {
    path.push(key);

    if (reference[key] === '--delete--' && object[key] !== undefined) {
      if (object[key] !== '--delete--') {
        messages.push(`chore(npm): delete ${path.join('.')}`);
      }
      delete object[key];
    } else {
      object[key] = deleter(object[key], reference[key], messages, path);
    }
    path.pop();
  });

  return object;
}

function removeKeyword(pkg, keywords, messages) {
  if (pkg.keywords !== undefined) {
    keywords.forEach(keyword => {
      if (pkg.keywords.find(k => k === keyword)) {
        messages.push(`docs(package): remove keyword ${keyword}`);
        pkg.keywords = pkg.keywords.filter(k => k !== keyword);
      }
    });

    if (pkg.keywords[0] === null || pkg.keywords[0] === undefined) {
      messages.push(`docs(package): remove keyword null`);
      pkg.keywords = [];
    }
  }
}

function addKeyword(pkg, regex, keyword, messages) {
  if (keyword === undefined || keyword === null || keyword === 'null') {
    return;
  }

  if (pkg.name.match(regex)) {
    if (pkg.keywords === undefined) {
      pkg.keywords = [];
    }
    if (!pkg.keywords.find(k => k === keyword)) {
      messages.push(`docs(package): add keyword ${keyword}`);
      pkg.keywords.push(keyword);
    }
  }
}
<commit_msg>refactor: make use of mergeContent(context, original, templateContent)<commit_after>import File from './file';

export default class Package extends File {
  async templateRepo(context) {
    const content = await this.originalContent(context, {
      ignoreMissing: true
    });
    const pkg = JSON.parse(content);
    if (pkg.template !== undefined && pkg.template.repository !== undefined) {
      const m = pkg.template.repository.url.match(/github.com\/(.*)\.git$/);
      return m[1];
    }

    return undefined;
  }

  async mergeContent(context, original, templateContent) {
    const originalLastChar = original[original.length - 1];

    let target =
      original === undefined || original === '' ? {} : JSON.parse(original);
    const template = JSON.parse(templateContent);
    const messages = [];
    const properties = context.properties;

    if (target.name === undefined || target.name === '') {
      const m = context.targetRepo.name.match(/^([^\/]+)\/(.*)/);
      target.name = m ? m[2] : context.targetRepo.name;
    }

    if (target.module !== undefined && !target.module.match(/\{\{module\}\}/)) {
      properties.module = target.module;
    }

    properties.main =
      target.main && !target.main.match(/\{\{main\}\}/)
        ? target.main
        : 'dist/index.js';

    const githubURL = `git+https://github.com/${properties.user}/${target.name}.git`;
    const githubURLAlternative = `git+https://github.com/${properties.user}/node-${target.name}.git`;

    let repoName = target.name;

    if (
      target.repository === undefined ||
      (target.repository.url !== githubURL &&
        target.repository.url !== githubURLAlternative)
    ) {
      target.repository = {
        type: 'git',
        url: githubURL
      };
      messages.push(`chore(package): correct github url`);
    }

    if (
      target.repository !== undefined &&
      githubURLAlternative === target.repository.url
    ) {
      repoName = `node-${target.name}`;
    }

    const bugsURL = `https://github.com/${properties.user}/${repoName}/issues`;

    if (target.bugs === undefined || target.bugs.url !== bugsURL) {
      target.bugs = {
        url: bugsURL
      };
      messages.push(`chore(package): correct bugs url`);
    }

    const homepageURL = `https://github.com/${properties.user}/${repoName}#readme`;

    if (target.homepage === undefined || target.homepage !== homepageURL) {
      target.homepage = homepageURL;
      messages.push(`chore(package): correct hompage url`);
    }

    let buildOutput;
    const extraBuilds = {};

    if (target.scripts !== undefined) {
      Object.keys(target.scripts).forEach(key => {
        const script = target.scripts[key];
        const ma = script.match(/--output=([^\s]+)/);
        if (ma) {
          buildOutput = ma[1];
        }

        const templateScript = template.scripts[key];
        if (templateScript !== undefined) {
          const mb = script.match(/&&\s*(.+)$/);
          if (mb && !templateScript.includes(mb[1])) {
            extraBuilds[key] = mb[1];
          }
        }
      });
    }

    const deepPropeties = {
      scripts: {},
      devDependencies: {},
      engines: {}
    };

    Object.keys(deepPropeties).forEach(p => {
      if (target[p] === undefined) {
        target[p] = {};
      }

      if (template[p] !== undefined) {
        Object.keys(template[p]).forEach(d => {
          if (template[p][d] === '-') {
            if (target[p][d] !== undefined) {
              messages.push(`chore(${p}): remove ${d}@${target[p][d]}`);
              delete target[p][d];
            }
          } else {
            const tp = context.expand(template[p][d]);
            if (tp !== target[p][d]) {
              messages.push(
                target[p][d] === undefined
                  ? `chore(${p}): add ${d}@${tp} from template`
                  : `chore(${p}): update ${d}@${tp} from template`
              );
              target[p][d] = tp;
            }
          }
        });
      }
    });

    Object.keys(template).forEach(p => {
      if (p !== 'template') {
        if (target[p] === undefined) {
          target[p] = template[p];
        }
      }
    });

    if (target.scripts.prepare) {
      if (buildOutput !== undefined) {
        target.scripts.prepare = target.scripts.prepare.replace(
          /--output=([^\s]+)/,
          `--output=${buildOutput}`
        );
      }
    }

    Object.keys(extraBuilds).forEach(key => {
      target.scripts[key] += ` && ${extraBuilds[key]}`;
    });

    if (target.module === '{{module}}') {
      delete target.module;
    }

    if (
      target.contributors !== undefined &&
      target.author !== undefined &&
      target.author.name !== undefined
    ) {
      const m = target.author.name.match(/(^[^<]+)<([^>]+)>/);
      if (m !== undefined) {
        const name = String(m[1]).replace(/^\s+|\s+$/g, '');
        const email = m[2];

        if (
          target.contributors.find(c => c.name === name && c.email === email)
        ) {
          delete target.author;
        }
      }
    }

    if (
      target.template === undefined ||
      target.template.repository === undefined ||
      target.template.repository.url !==
        `https://github.com/${context.templateRepo.name}.git`
    ) {
      messages.push('chore(package): set template repo');

      target.template = {
        repository: {
          url: `https://github.com/${context.templateRepo.name}.git`
        }
      };
    }

    // TODO loop over all rollup files
    const [modules1, modules2] = await Promise.all(
      ['rollup.config.js', 'tests/rollup.config.js'].map(async file => {
        const rcj = await context.files.get(file);
        if (rcj) {
          const m = await rcj.merge(context);
          return rcj.usedModules(m.content);
        }
        return new Set();
      })
    );

    Object.keys(target.devDependencies)
      .filter(m => {
        if (m.match(/rollup-plugin/)) {
          return modules1.has(m) || modules2.has(m) ? false : true;
        }

        return false;
      })
      .forEach(toBeRemoved => {
        delete target.devDependencies[toBeRemoved];
      });

    target = deleter(target, template, messages, []);

    if (target.keywords !== undefined) {
      delete target.keywords['npm-package-template'];
    }

    if (
      template.template !== undefined &&
      template.template.keywords !== undefined
    ) {
      Object.keys(template.template.keywords).forEach(r =>
        addKeyword(
          target,
          new RegExp(r),
          template.template.keywords[r],
          messages
        )
      );
    }

    removeKeyword(target, ['null', null, undefined], messages);

    if (messages.length === 0) {
      messages.push('chore: update package.json from template');
    }

    let newContent = JSON.stringify(context.expand(target), undefined, 2);
    const lastChar = newContent[newContent.length - 1];

    // keep trailing newline
    if (originalLastChar === '\n' && lastChar === '}') {
      newContent += '\n';
    }

    return {
      content: newContent,
      messages,
      path: this.path,
      changed: original !== newContent
    };
  }
}

function deleter(object, reference, messages, path) {
  if (
    typeof object === 'string' ||
    object instanceof String ||
    object === true ||
    object === false ||
    object === undefined ||
    object === null ||
    typeof object === 'number' ||
    object instanceof Number
  ) {
    return object;
  }

  Object.keys(reference).forEach(key => {
    path.push(key);

    if (reference[key] === '--delete--' && object[key] !== undefined) {
      if (object[key] !== '--delete--') {
        messages.push(`chore(npm): delete ${path.join('.')}`);
      }
      delete object[key];
    } else {
      object[key] = deleter(object[key], reference[key], messages, path);
    }
    path.pop();
  });

  return object;
}

function removeKeyword(pkg, keywords, messages) {
  if (pkg.keywords !== undefined) {
    keywords.forEach(keyword => {
      if (pkg.keywords.find(k => k === keyword)) {
        messages.push(`docs(package): remove keyword ${keyword}`);
        pkg.keywords = pkg.keywords.filter(k => k !== keyword);
      }
    });

    if (pkg.keywords[0] === null || pkg.keywords[0] === undefined) {
      messages.push(`docs(package): remove keyword null`);
      pkg.keywords = [];
    }
  }
}

function addKeyword(pkg, regex, keyword, messages) {
  if (keyword === undefined || keyword === null || keyword === 'null') {
    return;
  }

  if (pkg.name.match(regex)) {
    if (pkg.keywords === undefined) {
      pkg.keywords = [];
    }
    if (!pkg.keywords.find(k => k === keyword)) {
      messages.push(`docs(package): add keyword ${keyword}`);
      pkg.keywords.push(keyword);
    }
  }
}
<|endoftext|>


<commit_before>import { File } from './file';
import { diffVersion } from './util';
import { value } from 'jsonpath';
import diff from 'simple-diff';

function moduleNames(object) {
  if (object === undefined) return new Set();

  const modules = new Set();

  Object.keys(object).forEach(k => {
    const v = object[k];
    if (typeof v === 'string') {
      modules.add(v);
    } else if (Array.isArray(v)) {
      v.forEach(e => {
        if (typeof e === 'string') {
          modules.add(e);
        }
      });
    }
  });

  return modules;
}

/**
 * order in which json keys are written
 */
const sortedKeys = [
  'name',
  'version',
  'private',
  'publishConfig',
  'main',
  'browser',
  'module',
  'description',
  'keywords',
  'author',
  'maintainers',
  'contributors',
  'license',
  'bin',
  'scripts',
  'dependencies',
  'devDependencies',
  'peerDependencies',
  'optionalDependencies',
  'bundledDependencies',
  'engines',
  'os',
  'arch',
  'repository',
  'directories',
  'files',
  'man',
  'bugs',
  'homepage',
  'release',
  'ava',
  'nyc',
  'xo',
  'template'
];

/**
 * Merger for package.json
 */
export class Package extends File {
  static decodeScripts(scripts) {
    const decoded = {};

    if (scripts !== undefined) {
      Object.keys(scripts).forEach(key => {
        const script = scripts[key];
        decoded[key] = script.split(/\s*&&\s*/);
      });
    }

    return decoded;
  }

  static get defaultOptions() {
    return {
      actions: [],
      keywords: []
    };
  }

  static matchesFileName(name) {
    return name.match(/^package\.json$/);
  }

  optionalDevModules(modules = new Set()) {
    return new Set(['cracks', 'dont-crack'].filter(m => modules.has(m)));
  }

  async usedDevModules(content) {
    content = await content;

    const pkg = content.length === 0 ? {} : JSON.parse(content);

    return moduleNames(pkg.release);
  }

  /**
   * Deliver some key properties
   * @param {Branch} branch
   * @return {Object}
   */
  async properties(branch) {
    try {
      const content = await branch.content(this.path);
      const pkg = JSON.parse(content.content);

      const properties = {
        npm: { name: pkg.name, fullName: pkg.name }
      };

      if (pkg.name !== undefined) {
        const m = pkg.name.match(/^(\@[^\/]+)\/(.*)/);
        if (m) {
          properties.npm.organization = m[1];
          properties.npm.name = m[2];
        }
      }

      if (pkg.template !== undefined && pkg.template.repository !== undefined) {
        properties.templateRepo = pkg.template.repository.url;
      }

      ['description', 'name', 'module', 'browser', 'version'].forEach(key => {
        if (pkg[key] !== undefined && pkg[key] !== `{{${key}}}`) {
          if (!(key === 'version' && pkg[key] === '0.0.0-semantic-release')) {
            properties[key] = pkg[key];
          }
        }
      });

      return properties;
    } catch (e) {}

    return {};
  }

  async mergeContent(context, original, templateContent) {
    const originalLastChar = original[original.length - 1];
    const originalTemplate = JSON.parse(templateContent);

    const targetRepository = context.targetBranch.repository;

    let target =
      original === undefined || original === '' ? {} : JSON.parse(original);

    const template = Object.assign({}, originalTemplate, {
      repository: {
        type: targetRepository.type,
        url: targetRepository.url
      },
      bugs: {
        url: context.targetBranch.issuesURL
      },
      homepage: context.targetBranch.homePageURL,
      template: {
        repository: {
          url: context.templateBranch.url
        }
      }
    });
    template.template = Object.assign({}, target.template, template.template);

    let messages = [];
    const properties = context.properties;

    if (target.name === undefined || target.name === '') {
      const m = targetRepository.name.match(/^([^\/]+)\/(.*)/);
      target.name = m ? m[2] : context.targetBranch.name;
    }

    if (target.module !== undefined && !target.module.match(/\{\{module\}\}/)) {
      properties.module = target.module;
    }

    properties.main =
      target.main && !target.main.match(/\{\{main\}\}/)
        ? target.main
        : 'dist/index.js';

    const slots = {
      repository: 'chore(package): correct repository url',
      bugs: 'chore(package): correct bugs url',
      homepage: 'chore(package): homepage',
      template: 'chore(package): set template repo'
    };
    Object.keys(slots).forEach(key => {
      if (
        template[key] !== undefined &&
        diff(target[key], template[key]).length > 0
      ) {
        messages.push(slots[key]);
        target[key] = template[key];
      }
    });

    const extraBuilds = {};

    if (target.scripts !== undefined) {
      Object.keys(target.scripts).forEach(key => {
        const script = target.scripts[key];

        if (template.scripts !== undefined) {
          const templateScript = template.scripts[key];
          if (templateScript !== undefined) {
            //const parts = script.split(/\s*&&\s*/);
            const mb = script.match(/&&\s*(.+)$/);
            if (mb && !templateScript.includes(mb[1])) {
              extraBuilds[key] = mb[1];
            }
          }
        }
      });
    }

    const usedDevModules = await context.usedDevModules();

    //context.debug(`usedDevModules: ${Array.from(usedDevModules).join(',')}`);

    const optionalDevModules = context.optionalDevModules(usedDevModules);

    /*context.debug(
      `optionalDevModules: ${Array.from(optionalDevModules).join(',')}`
    );*/

    const deepProperties = {
      devDependencies: { type: 'chore', scope: 'package', merge: defaultMerge },
      dependencies: { type: 'fix', scope: 'package', merge: defaultMerge },
      peerDependencies: { type: 'fix', scope: 'package', merge: defaultMerge },
      optionalDependencies: {
        type: 'fix',
        scope: 'package',
        merge: defaultMerge
      },
      bundeledDependencies: {
        type: 'fix',
        scope: 'package',
        merge: defaultMerge
      },
      scripts: { type: 'chore', scope: 'scripts', merge: defaultMerge },
      engines: { type: 'chore', scope: 'engines', merge: defaultMerge }
    };

    Object.keys(deepProperties).forEach(
      name => (deepProperties[name].name = name)
    );

    Object.keys(deepProperties).forEach(category => {
      if (template[category] !== undefined) {
        Object.keys(template[category]).forEach(d => {
          if (target[category] === undefined) {
            target[category] = {};
          }

          const tp = context.expand(template[category][d]);
          if (
            category === 'devDependencies' &&
            target.dependencies !== undefined &&
            target.dependencies[d] === tp
          ) {
            // do not include dev dependency if regular dependency is already present
          } else {
            deepProperties[category].merge(
              target[category],
              target[category][d],
              tp,
              deepProperties[category],
              d,
              messages
            );
          }
        });
      }
    });

    Object.keys(template).forEach(p => {
      if (target[p] === undefined) {
        target[p] = template[p];
        messages.push(`chore(package): add ${p} from template`);
      }
    });

    Object.keys(extraBuilds).forEach(key => {
      target.scripts[key] += ` && ${extraBuilds[key]}`;
    });

    if (target.module === '{{module}}') {
      delete target.module;
    }

    if (
      target.contributors !== undefined &&
      target.author !== undefined &&
      target.author.name !== undefined
    ) {
      const m = target.author.name.match(/(^[^<]+)<([^>]+)>/);
      if (m !== undefined) {
        const name = String(m[1]).replace(/^\s+|\s+$/g, '');
        const email = m[2];

        if (
          target.contributors.find(c => c.name === name && c.email === email)
        ) {
          delete target.author;
        }
      }
    }

    const toBeDeletedModules =
      target.devDependencies === undefined
        ? []
        : Array.from(
            context.optionalDevModules(
              new Set(Object.keys(target.devDependencies))
            )
          ).filter(m => !usedDevModules.has(m));

    toBeDeletedModules.forEach(d => {
      messages = messages.filter(
        m => !m.startsWith(`chore(package): add ${d}@`)
      );
      delete target.devDependencies[d];
    });

    target = deleter(target, template, messages, []);

    if (target.keywords !== undefined) {
      delete target.keywords['npm-package-template'];
    }

    Object.keys(this.options.keywords).forEach(r =>
      addKeyword(target, new RegExp(r), this.options.keywords[r], messages)
    );

    removeKeyword(target, ['null', null, undefined], messages);

    this.options.actions.forEach(action => {
      if (action.op === 'replace') {
        const v = value(template, action.path);
        if (v !== undefined) {
          const oldValue = value(target, action.path);
          if (oldValue !== v) {
            value(target, action.path, v);
            messages.push(
              `chore(package): set ${action.path}='${v}' as in template`
            );
          }
        }
      }
    });

    target = context.expand(target);
    const sortedTarget = normalizePackage(target);

    let newContent = JSON.stringify(sortedTarget, undefined, 2);
    const lastChar = newContent[newContent.length - 1];

    // keep trailing newline
    if (originalLastChar === '\n' && lastChar === '}') {
      newContent += '\n';
    }

    /*
    console.log(original);
    console.log(newContent);
*/
    const changed = original !== newContent;

    if (changed && messages.length === 0) {
      messages.push('chore(package): update package.json from template');
    }

    return {
      content: newContent,
      messages,
      changed
    };
  }
}

function deleter(object, reference, messages, path) {
  if (
    typeof object === 'string' ||
    object instanceof String ||
    object === true ||
    object === false ||
    object === undefined ||
    object === null ||
    typeof object === 'number' ||
    object instanceof Number
  ) {
    return object;
  }

  if (Array.isArray(object)) {
    return object.map((e, i) => {
      path.push(i);
      const n = deleter(
        object[i],
        Array.isArray(reference) ? reference[i] : undefined,
        messages,
        path
      );
      path.pop();
      return n;
    });
  }

  if (reference) {
    Object.keys(reference).forEach(key => {
      path.push(key);

      if (reference[key] === '--delete--' && object[key] !== undefined) {
        if (object[key] !== '--delete--') {
          messages.push(`chore(npm): delete ${path.join('.')}`);
        }
        delete object[key];
      } else {
        object[key] = deleter(object[key], reference[key], messages, path);
      }
      path.pop();
    });
  }

  return object;
}

function removeKeyword(pkg, keywords, messages) {
  if (pkg.keywords !== undefined) {
    keywords.forEach(keyword => {
      if (pkg.keywords.find(k => k === keyword)) {
        messages.push(`docs(package): remove keyword ${keyword}`);
        pkg.keywords = pkg.keywords.filter(k => k !== keyword);
      }
    });

    if (
      (pkg.keywords.length === 1 && pkg.keywords[0] === null) ||
      pkg.keywords[0] === undefined
    ) {
      messages.push(`docs(package): remove keyword null`);
      pkg.keywords = [];
    }
  }
}

function addKeyword(pkg, regex, keyword, messages) {
  if (keyword === undefined || keyword === null || keyword === 'null') {
    return;
  }

  if (pkg.name.match(regex)) {
    if (pkg.keywords === undefined) {
      pkg.keywords = [];
    }
    if (!pkg.keywords.find(k => k === keyword)) {
      messages.push(`docs(package): add keyword ${keyword}`);
      pkg.keywords.push(keyword);
    }
  }
}

function getVersion(e) {
  const m = e.match(/([\d\.]+)/);
  return m ? Number(m[1]) : undefined;
}

function normalizeVersion(e) {
  return e.replace(/^[\^\$]/, '');
}

/**
 *
 */
function defaultMerge(destination, target, template, dp, name, messages) {
  if (template === '-') {
    if (target !== undefined) {
      messages.push(`${dp.type}(${dp.scope}): remove ${name}@${target}`);
      delete destination[name];
    }

    return;
  }

  if (target === undefined) {
    messages.push(`${dp.type}(${dp.scope}): add ${name}@${template}`);
    destination[name] = template;
  } else if (template !== target) {
    if (dp.name === 'engines') {
      if (getVersion(target) > getVersion(template)) {
        return;
      }
    }
    if (dp.name === 'devDependencies') {
      if (
        diffVersion(normalizeVersion(target), normalizeVersion(template)) >= 0
      ) {
        return;
      }
    }

    messages.push(`${dp.type}(${dp.scope}): ${name}@${template}`);

    destination[name] = template;
  }
}

/**
 * bring package into nomalized (sorted) form
 * @param {Object} source
 * @return {Object} normalized source
 */
function normalizePackage(source) {
  const normalized = {};

  sortedKeys.forEach(key => {
    if (source[key] !== undefined) {
      normalized[key] = source[key];
    }
  });

  Object.keys(source).forEach(key => {
    if (normalized[key] === undefined) {
      normalized[key] = source[key];
    }
  });

  return normalized;
}
<commit_msg>fix(package): enhance repo, bugs, hompage messages<commit_after>import { File } from './file';
import { diffVersion } from './util';
import { value } from 'jsonpath';
import diff from 'simple-diff';

function moduleNames(object) {
  if (object === undefined) return new Set();

  const modules = new Set();

  Object.keys(object).forEach(k => {
    const v = object[k];
    if (typeof v === 'string') {
      modules.add(v);
    } else if (Array.isArray(v)) {
      v.forEach(e => {
        if (typeof e === 'string') {
          modules.add(e);
        }
      });
    }
  });

  return modules;
}

/**
 * order in which json keys are written
 */
const sortedKeys = [
  'name',
  'version',
  'private',
  'publishConfig',
  'main',
  'browser',
  'module',
  'description',
  'keywords',
  'author',
  'maintainers',
  'contributors',
  'license',
  'bin',
  'scripts',
  'dependencies',
  'devDependencies',
  'peerDependencies',
  'optionalDependencies',
  'bundledDependencies',
  'engines',
  'os',
  'arch',
  'repository',
  'directories',
  'files',
  'man',
  'bugs',
  'homepage',
  'release',
  'ava',
  'nyc',
  'xo',
  'template'
];

/**
 * Merger for package.json
 */
export class Package extends File {
  static decodeScripts(scripts) {
    const decoded = {};

    if (scripts !== undefined) {
      Object.keys(scripts).forEach(key => {
        const script = scripts[key];
        decoded[key] = script.split(/\s*&&\s*/);
      });
    }

    return decoded;
  }

  static get defaultOptions() {
    return {
      actions: [],
      keywords: []
    };
  }

  static matchesFileName(name) {
    return name.match(/^package\.json$/);
  }

  optionalDevModules(modules = new Set()) {
    return new Set(['cracks', 'dont-crack'].filter(m => modules.has(m)));
  }

  async usedDevModules(content) {
    content = await content;

    const pkg = content.length === 0 ? {} : JSON.parse(content);

    return moduleNames(pkg.release);
  }

  /**
   * Deliver some key properties
   * @param {Branch} branch
   * @return {Object}
   */
  async properties(branch) {
    try {
      const content = await branch.content(this.path);
      const pkg = JSON.parse(content.content);

      const properties = {
        npm: { name: pkg.name, fullName: pkg.name }
      };

      if (pkg.name !== undefined) {
        const m = pkg.name.match(/^(\@[^\/]+)\/(.*)/);
        if (m) {
          properties.npm.organization = m[1];
          properties.npm.name = m[2];
        }
      }

      if (pkg.template !== undefined && pkg.template.repository !== undefined) {
        properties.templateRepo = pkg.template.repository.url;
      }

      ['description', 'name', 'module', 'browser', 'version'].forEach(key => {
        if (pkg[key] !== undefined && pkg[key] !== `{{${key}}}`) {
          if (!(key === 'version' && pkg[key] === '0.0.0-semantic-release')) {
            properties[key] = pkg[key];
          }
        }
      });

      return properties;
    } catch (e) {}

    return {};
  }

  async mergeContent(context, original, templateContent) {
    const originalLastChar = original[original.length - 1];
    const originalTemplate = JSON.parse(templateContent);

    const targetRepository = context.targetBranch.repository;

    let target =
      original === undefined || original === '' ? {} : JSON.parse(original);

    const template = Object.assign({}, originalTemplate, {
      repository: {
        type: targetRepository.type,
        url: targetRepository.url
      },
      bugs: {
        url: context.targetBranch.issuesURL
      },
      homepage: context.targetBranch.homePageURL,
      template: {
        repository: {
          url: context.templateBranch.url
        }
      }
    });
    template.template = Object.assign({}, target.template, template.template);

    let messages = [];
    const properties = context.properties;

    if (target.name === undefined || target.name === '') {
      const m = targetRepository.name.match(/^([^\/]+)\/(.*)/);
      target.name = m ? m[2] : context.targetBranch.name;
    }

    if (target.module !== undefined && !target.module.match(/\{\{module\}\}/)) {
      properties.module = target.module;
    }

    properties.main =
      target.main && !target.main.match(/\{\{main\}\}/)
        ? target.main
        : 'dist/index.js';

    const slots = {
      repository: 'chore(package): correct repository url',
      bugs: 'chore(package): set bugs url from template',
      homepage: 'chore(package): homepage from template',
      template: 'chore(package): set template repo'
    };
    Object.keys(slots).forEach(key => {
      const templateValue = template[key];
      if (
        templateValue !== undefined &&
        diff(target[key], templateValue).length > 0
      ) {
        console.log(target[key]);
        console.log(templateValue);
        console.log(diff(target[key], templateValue));
        messages.push(slots[key]);
        target[key] = templateValue;
      }
    });

    const extraBuilds = {};

    if (target.scripts !== undefined) {
      Object.keys(target.scripts).forEach(key => {
        const script = target.scripts[key];

        if (template.scripts !== undefined) {
          const templateScript = template.scripts[key];
          if (templateScript !== undefined) {
            //const parts = script.split(/\s*&&\s*/);
            const mb = script.match(/&&\s*(.+)$/);
            if (mb && !templateScript.includes(mb[1])) {
              extraBuilds[key] = mb[1];
            }
          }
        }
      });
    }

    const usedDevModules = await context.usedDevModules();

    //context.debug(`usedDevModules: ${Array.from(usedDevModules).join(',')}`);

    const optionalDevModules = context.optionalDevModules(usedDevModules);

    /*context.debug(
      `optionalDevModules: ${Array.from(optionalDevModules).join(',')}`
    );*/

    const deepProperties = {
      devDependencies: { type: 'chore', scope: 'package', merge: defaultMerge },
      dependencies: { type: 'fix', scope: 'package', merge: defaultMerge },
      peerDependencies: { type: 'fix', scope: 'package', merge: defaultMerge },
      optionalDependencies: {
        type: 'fix',
        scope: 'package',
        merge: defaultMerge
      },
      bundeledDependencies: {
        type: 'fix',
        scope: 'package',
        merge: defaultMerge
      },
      scripts: { type: 'chore', scope: 'scripts', merge: defaultMerge },
      engines: { type: 'chore', scope: 'engines', merge: defaultMerge }
    };

    Object.keys(deepProperties).forEach(
      name => (deepProperties[name].name = name)
    );

    Object.keys(deepProperties).forEach(category => {
      if (template[category] !== undefined) {
        Object.keys(template[category]).forEach(d => {
          if (target[category] === undefined) {
            target[category] = {};
          }

          const tp = context.expand(template[category][d]);
          if (
            category === 'devDependencies' &&
            target.dependencies !== undefined &&
            target.dependencies[d] === tp
          ) {
            // do not include dev dependency if regular dependency is already present
          } else {
            deepProperties[category].merge(
              target[category],
              target[category][d],
              tp,
              deepProperties[category],
              d,
              messages
            );
          }
        });
      }
    });

    Object.keys(template).forEach(p => {
      if (target[p] === undefined) {
        target[p] = template[p];
        messages.push(`chore(package): add ${p} from template`);
      }
    });

    Object.keys(extraBuilds).forEach(key => {
      target.scripts[key] += ` && ${extraBuilds[key]}`;
    });

    if (target.module === '{{module}}') {
      delete target.module;
    }

    if (
      target.contributors !== undefined &&
      target.author !== undefined &&
      target.author.name !== undefined
    ) {
      const m = target.author.name.match(/(^[^<]+)<([^>]+)>/);
      if (m !== undefined) {
        const name = String(m[1]).replace(/^\s+|\s+$/g, '');
        const email = m[2];

        if (
          target.contributors.find(c => c.name === name && c.email === email)
        ) {
          delete target.author;
        }
      }
    }

    const toBeDeletedModules =
      target.devDependencies === undefined
        ? []
        : Array.from(
            context.optionalDevModules(
              new Set(Object.keys(target.devDependencies))
            )
          ).filter(m => !usedDevModules.has(m));

    toBeDeletedModules.forEach(d => {
      messages = messages.filter(
        m => !m.startsWith(`chore(package): add ${d}@`)
      );
      delete target.devDependencies[d];
    });

    target = deleter(target, template, messages, []);

    if (target.keywords !== undefined) {
      delete target.keywords['npm-package-template'];
    }

    Object.keys(this.options.keywords).forEach(r =>
      addKeyword(target, new RegExp(r), this.options.keywords[r], messages)
    );

    removeKeyword(target, ['null', null, undefined], messages);

    this.options.actions.forEach(action => {
      if (action.op === 'replace') {
        const v = value(template, action.path);
        if (v !== undefined) {
          const oldValue = value(target, action.path);
          if (oldValue !== v) {
            value(target, action.path, v);
            messages.push(
              `chore(package): set ${action.path}='${v}' as in template`
            );
          }
        }
      }
    });

    target = context.expand(target);
    const sortedTarget = normalizePackage(target);

    let newContent = JSON.stringify(sortedTarget, undefined, 2);
    const lastChar = newContent[newContent.length - 1];

    // keep trailing newline
    if (originalLastChar === '\n' && lastChar === '}') {
      newContent += '\n';
    }

    /*
    console.log(original);
    console.log(newContent);
*/
    const changed = original !== newContent;

    if (changed && messages.length === 0) {
      messages.push('chore(package): update package.json from template');
    }

    return {
      content: newContent,
      messages,
      changed
    };
  }
}

function deleter(object, reference, messages, path) {
  if (
    typeof object === 'string' ||
    object instanceof String ||
    object === true ||
    object === false ||
    object === undefined ||
    object === null ||
    typeof object === 'number' ||
    object instanceof Number
  ) {
    return object;
  }

  if (Array.isArray(object)) {
    return object.map((e, i) => {
      path.push(i);
      const n = deleter(
        object[i],
        Array.isArray(reference) ? reference[i] : undefined,
        messages,
        path
      );
      path.pop();
      return n;
    });
  }

  if (reference) {
    Object.keys(reference).forEach(key => {
      path.push(key);

      if (reference[key] === '--delete--' && object[key] !== undefined) {
        if (object[key] !== '--delete--') {
          messages.push(`chore(npm): delete ${path.join('.')}`);
        }
        delete object[key];
      } else {
        object[key] = deleter(object[key], reference[key], messages, path);
      }
      path.pop();
    });
  }

  return object;
}

function removeKeyword(pkg, keywords, messages) {
  if (pkg.keywords !== undefined) {
    keywords.forEach(keyword => {
      if (pkg.keywords.find(k => k === keyword)) {
        messages.push(`docs(package): remove keyword ${keyword}`);
        pkg.keywords = pkg.keywords.filter(k => k !== keyword);
      }
    });

    if (
      (pkg.keywords.length === 1 && pkg.keywords[0] === null) ||
      pkg.keywords[0] === undefined
    ) {
      messages.push(`docs(package): remove keyword null`);
      pkg.keywords = [];
    }
  }
}

function addKeyword(pkg, regex, keyword, messages) {
  if (keyword === undefined || keyword === null || keyword === 'null') {
    return;
  }

  if (pkg.name.match(regex)) {
    if (pkg.keywords === undefined) {
      pkg.keywords = [];
    }
    if (!pkg.keywords.find(k => k === keyword)) {
      messages.push(`docs(package): add keyword ${keyword}`);
      pkg.keywords.push(keyword);
    }
  }
}

function getVersion(e) {
  const m = e.match(/([\d\.]+)/);
  return m ? Number(m[1]) : undefined;
}

function normalizeVersion(e) {
  return e.replace(/^[\^\$]/, '');
}

/**
 *
 */
function defaultMerge(destination, target, template, dp, name, messages) {
  if (template === '-') {
    if (target !== undefined) {
      messages.push(`${dp.type}(${dp.scope}): remove ${name}@${target}`);
      delete destination[name];
    }

    return;
  }

  if (target === undefined) {
    messages.push(`${dp.type}(${dp.scope}): add ${name}@${template}`);
    destination[name] = template;
  } else if (template !== target) {
    if (dp.name === 'engines') {
      if (getVersion(target) > getVersion(template)) {
        return;
      }
    }
    if (dp.name === 'devDependencies') {
      if (
        diffVersion(normalizeVersion(target), normalizeVersion(template)) >= 0
      ) {
        return;
      }
    }

    messages.push(`${dp.type}(${dp.scope}): ${name}@${template}`);

    destination[name] = template;
  }
}

/**
 * bring package into nomalized (sorted) form
 * @param {Object} source
 * @return {Object} normalized source
 */
function normalizePackage(source) {
  const normalized = {};

  sortedKeys.forEach(key => {
    if (source[key] !== undefined) {
      normalized[key] = source[key];
    }
  });

  Object.keys(source).forEach(key => {
    if (normalized[key] === undefined) {
      normalized[key] = source[key];
    }
  });

  return normalized;
}
<|endoftext|>


<commit_before>/* Copyright 2015 Dietrich Epp.

   This file is part of Dash and the Jetpack Space Pirates.  The Dash
   and the Jetpack Space Pirates source code is distributed under the
   terms of the MIT license.  See LICENSE.txt for details. */
'use strict';

var param = require('./param');

// GroundAngle expressed as a dot product
var GroundThreshold = Math.cos(param.Game.GroundAngle * (Math.PI / 180));

/*
 * Materials
 */
var Material = {
	World: new p2.Material(),
	Player: new p2.Material(),
};

/*
 * Contact materials (private)
 */
var Contact = [
	new p2.ContactMaterial(Material.Player, Material.World, {
		friction: param.Game.Friction,
	}),
];

/*
 * Collision masks
 */
var Mask = {
	// The world and obstacles
	World: 1,
	// The player and player shots
	Player: 2,
	// The enemy and enemy shots
	Enemy: 4,
	// Items
	Item: 8,
};

/*
	World mask: Player | Enemy
	Player mask: World | Enemy
	Enemy mask: World | Enemy
	Item mask: Player
*/

/*
 * Calculate the interpolated position of a body.
 */
function bodyPos(body, frac) {
	// P2 can do this for us, but we will figure that out later.
	var p = body.position, pp = body.previousPosition;
	return [pp[0] + (p[0] - pp[0]) * frac, pp[1] + (p[1] - pp[1]) * frac];
}

/*
 * Reset the world.
 */
function resetWorld(world) {
	var g = param.Game, i;
	world.clear();
	world.gravity[1] = - g.Gravity;
	for (i = 0; i < Contact.length; i++) {
		world.addContactMaterial(Contact[i]);
	}
}

/*
 * Run the simulation until all bodies are settled.
 *
 * world: The world
 * dt: Timestep
 * maxTime: Maximum settling time
 */
function settle(world, dt, maxTime) {
	var oldSleep = world.sleepMode;
	world.sleepMode = p2.World.BODY_SLEEPING;
	var bodies = world.bodies, i, b;
	var iter, maxIter = Math.ceil(maxTime / dt);
	/*jshint -W018*/
	if (!(maxIter < 1000)) {
		maxIter = 1000;
	}
	if (!(maxIter > 0)) {
		maxIter = 1;
	}
	var SLEEPING = p2.Body.SLEEPING, STATIC = p2.Body.STATIC;
	var numAwake;
	for (iter = 0; iter < maxIter; iter++) {
		numAwake = 0;
		for (i = 0; i < bodies.length; i++) {
			b = bodies[i];
			if (b.type !== STATIC && b.sleepState !== SLEEPING) {
				numAwake++;
			}
		}
		if (numAwake === 0) {
			break;
		}
		world.step(dt);
	}
	if (iter >= maxIter) {
		console.warn('Could not settle simulation, awake:', numAwake);
	} else {
		// console.log('Settling time: ', iter * dt);
	}
	var AWAKE = p2.Body.AWAKE;
	for (i = 0; i < bodies.length; i++) {
		bodies[i].sleepState = AWAKE;
	}
	// Doesn't work without waking all the bodies up
	world.sleepMode = oldSleep;
}

/*
 * Test wether a body is touching the ground.
 */
function isGrounded(world, body) {
	if (body.sleepState === body.SLEEPING) {
		return true;
	}
	var eqs = world.narrowphase.contactEquations;
	var thresh = GroundThreshold;
	for (var i = 0; i < eqs.length; i++){
		var eq = eqs[i];
		if (eq.bodyA === body) {
			if (-eq.normalA[1] >= thresh) {
				return true;
			}
		} else if (eq.bodyB === body) {
			if (eq.normalA[1] >= thresh) {
				return true;
			}
		}
	}
	return false;
}

module.exports = {
	Material: Material,
	Mask: Mask,
	bodyPos: bodyPos,
	resetWorld: resetWorld,
	settle: settle,
	isGrounded: isGrounded,
};
<commit_msg>cleanup: remove dead code<commit_after>/* Copyright 2015 Dietrich Epp.

   This file is part of Dash and the Jetpack Space Pirates.  The Dash
   and the Jetpack Space Pirates source code is distributed under the
   terms of the MIT license.  See LICENSE.txt for details. */
'use strict';

var param = require('./param');

// GroundAngle expressed as a dot product
var GroundThreshold = Math.cos(param.Game.GroundAngle * (Math.PI / 180));

/*
 * Materials
 */
var Material = {
	World: new p2.Material(),
	Player: new p2.Material(),
};

/*
 * Contact materials (private)
 */
var Contact = [
	new p2.ContactMaterial(Material.Player, Material.World, {
		friction: param.Game.Friction,
	}),
];

/*
 * Collision masks
 */
var Mask = {
	// The world and obstacles
	World: 1,
	// The player and player shots
	Player: 2,
	// The enemy and enemy shots
	Enemy: 4,
	// Items
	Item: 8,
};

/*
	World mask: Player | Enemy
	Player mask: World | Enemy
	Enemy mask: World | Enemy
	Item mask: Player
*/

/*
 * Reset the world.
 */
function resetWorld(world) {
	var g = param.Game, i;
	world.clear();
	world.gravity[1] = - g.Gravity;
	for (i = 0; i < Contact.length; i++) {
		world.addContactMaterial(Contact[i]);
	}
}

/*
 * Run the simulation until all bodies are settled.
 *
 * world: The world
 * dt: Timestep
 * maxTime: Maximum settling time
 */
function settle(world, dt, maxTime) {
	var oldSleep = world.sleepMode;
	world.sleepMode = p2.World.BODY_SLEEPING;
	var bodies = world.bodies, i, b;
	var iter, maxIter = Math.ceil(maxTime / dt);
	/*jshint -W018*/
	if (!(maxIter < 1000)) {
		maxIter = 1000;
	}
	if (!(maxIter > 0)) {
		maxIter = 1;
	}
	var SLEEPING = p2.Body.SLEEPING, STATIC = p2.Body.STATIC;
	var numAwake;
	for (iter = 0; iter < maxIter; iter++) {
		numAwake = 0;
		for (i = 0; i < bodies.length; i++) {
			b = bodies[i];
			if (b.type !== STATIC && b.sleepState !== SLEEPING) {
				numAwake++;
			}
		}
		if (numAwake === 0) {
			break;
		}
		world.step(dt);
	}
	if (iter >= maxIter) {
		console.warn('Could not settle simulation, awake:', numAwake);
	} else {
		// console.log('Settling time: ', iter * dt);
	}
	var AWAKE = p2.Body.AWAKE;
	for (i = 0; i < bodies.length; i++) {
		bodies[i].sleepState = AWAKE;
	}
	// Doesn't work without waking all the bodies up
	world.sleepMode = oldSleep;
}

/*
 * Test wether a body is touching the ground.
 */
function isGrounded(world, body) {
	if (body.sleepState === body.SLEEPING) {
		return true;
	}
	var eqs = world.narrowphase.contactEquations;
	var thresh = GroundThreshold;
	for (var i = 0; i < eqs.length; i++){
		var eq = eqs[i];
		if (eq.bodyA === body) {
			if (-eq.normalA[1] >= thresh) {
				return true;
			}
		} else if (eq.bodyB === body) {
			if (eq.normalA[1] >= thresh) {
				return true;
			}
		}
	}
	return false;
}

module.exports = {
	Material: Material,
	Mask: Mask,
	resetWorld: resetWorld,
	settle: settle,
	isGrounded: isGrounded,
};
<|endoftext|>


<commit_before>var Pumpkin = function()
{
	this.data = null;
	this.works = {};
};

Pumpkin.prototype.setData = function(data)
{
	this.data = data;
};

Pumpkin.prototype.addWork = function(name, work)
{
	this.works[name] = work;
};

Pumpkin.prototype.execute = function(list, done, error, index, params)
{
	if(list)
	{
		try
		{
			if(!index)
				index = 0;

			if(typeof index == 'object')
			{
				params = index;
				index = 0;
			}

			if(list.length == index)
			{
				done.call({data : this.data}, params);
				return;
			}

			var that = this;
			var name = list[index];
			if(typeof name == 'object')
			{
				params = params ? params : {};
				for(var key in name.params)
				{
					params[key] = name.params[key];
				}

				name = name.name;
			}

			var work = this.works[name];

			work.call({data : this.data, next : function(params)
			{
				that.execute(list, done, error, index+1, params);
			}, error : function(err)
			{
				if(error)
					error(list[index], err);
			}}, params);
		}
		catch(err)
		{
			if(error)
				error(name, err);
		}
	}
	else
	{
		console.log('pumpkin.execute - First arguments must not be null.');
	}
};

try
{
	module.exports = Pumpkin;
}
catch(err)
{}<commit_msg>Fixed bugs<commit_after>var Pumpkin = function()
{
	this.data = null;
	this.works = {};
};

Pumpkin.prototype.setData = function(data)
{
	this.data = data;
};

Pumpkin.prototype.addWork = function(name, work)
{
	this.works[name] = work;
};

Pumpkin.prototype.execute = function(list, done, error, index, params)
{
	if(list)
	{
		try
		{
			if(!index)
				index = 0;

			if(typeof index == 'object')
			{
				params = index;
				index = 0;
			}

			if(list.length == index)
			{
				if(done)
					done.call({data : this.data}, params);

				return;
			}

			var that = this;
			var name = list[index];
			if(typeof name == 'object')
			{
				params = params ? params : {};
				for(var key in name.params)
				{
					params[key] = name.params[key];
				}

				name = name.name;
			}

			var work = this.works[name];

			if(work)
			{
				work.call({data : this.data, next : function(params)
				{
					that.execute(list, done, error, index+1, params);
				}, error : function(err)
				{
					if(error)
						error(list[index], err);
				}}, params);
			}
		}
		catch(err)
		{
			if(error)
				error(name, err);
		}
	}
	else
	{
		console.log('pumpkin.execute - First arguments must not be null.');
	}
};

try
{
	module.exports = Pumpkin;
}
catch(err)
{}<|endoftext|>


<commit_before>import omit from 'lodash/omit';
import isEmpty from 'lodash/isEmpty';
import mapValues from 'lodash/mapValues';

import * as EntitiesActions from './actions';
import {
  update,
  defaultTo,
} from './utils';

function reducer(state, action) {
  const testing = process.env.NODE_ENV === 'test';
  if ( ! testing && (! action.meta || ! action.meta.entityAction)) return state;
  action = testing ? action : action.meta.entityAction;
  switch (action.type) {
    case EntitiesActions.CREATE_ENTITIES:
    case EntitiesActions.CREATE_ENTITY: {
      const { entities } = action.payload.data;
      return mapValues(state, (currentEntities, key) => ({
        ...currentEntities,
        ...entities[key],
      }));
    }
    case EntitiesActions.UPDATE_ENTITY: {
      const { data, id, key, useDefault } = action.payload;
      const newData = data.entities[key][id];
      return {
        ...state,
        [key]: {
          ...state[key],
          [id]: useDefault ? defaultTo(state[key][id], newData) : update(state[key][id], newData),
        },
      };
    }
    case EntitiesActions.UPDATE_ENTITIES: {
      const { data, ids, key } = action.payload;
      return ids.reduce((memo, id) => {
        const newData = data.entities[key][id];
        return {
          ...memo,
          [key]: {
            ...memo[key],
            [id]: update(memo[key][id], newData),
          },
        };
      }, state);
    }
    case EntitiesActions.UPDATE_ENTITY_ID: {
      const { key, schema, oldId, newId } = action.payload;
      const updatedEntity = { ...state[key][oldId], id: newId };
      return mapValues(state, (currentEntities, key) => {
        // The entities we need to update
        if (key === schema.getKey()) {
          return omit({
            ...currentEntities,
            [newId]: updatedEntity,
          }, oldId);
        }
        // No related entities, so no need to perform any update
        if ( ! schema.isRelatedTo(key)) {
          return currentEntities;
        }
        // The entities are related
        const { isParent, relatedPropName } = schema.getRelation(updatedEntity, key);
        if (isParent) {
          // TODO: The entity is a OneToOne relation
          return currentEntities;
        }
        // The entities are the 'many' part in a OneToMany relation
        return mapValues(currentEntities, (entity) => {
          if (entity[relatedPropName] !== oldId) {
            return entity;
          }
          return {
            ...entity,
            [relatedPropName]: newId,
          };
        });
      });
    }
    case EntitiesActions.DELETE_ENTITY: {
      const { key, id } = action.payload;
      return {
        ...state,
        [key]: omit(state[key], id),
      };
    }
    default:
      return state;
  }
}

export default function entities(schemas) {
  if (isEmpty(schemas)) {
    throw new Error('[INVALID SCHEMAS]');
  }
  const emptyEntities = mapValues(schemas, () => ({}));
  return (state=emptyEntities, action) => reducer(state, action);
}
<commit_msg>Prevent updating id during UPDATE_ENTITY<commit_after>import omit from 'lodash/omit';
import isEmpty from 'lodash/isEmpty';
import mapValues from 'lodash/mapValues';

import * as EntitiesActions from './actions';
import {
  update,
  defaultTo,
} from './utils';

function reducer(state, action) {
  const testing = process.env.NODE_ENV === 'test';
  if ( ! testing && (! action.meta || ! action.meta.entityAction)) return state;
  action = testing ? action : action.meta.entityAction;
  switch (action.type) {
    case EntitiesActions.CREATE_ENTITIES:
    case EntitiesActions.CREATE_ENTITY: {
      const { entities } = action.payload.data;
      return mapValues(state, (currentEntities, key) => ({
        ...currentEntities,
        ...entities[key],
      }));
    }
    case EntitiesActions.UPDATE_ENTITY: {
      const { data, id, key, useDefault } = action.payload;
      const newData = data.entities[key][id];
      delete newData.id;
      return {
        ...state,
        [key]: {
          ...state[key],
          [id]: useDefault ? defaultTo(state[key][id], newData) : update(state[key][id], newData),
        },
      };
    }
    case EntitiesActions.UPDATE_ENTITIES: {
      const { data, ids, key } = action.payload;
      return ids.reduce((memo, id) => {
        const newData = data.entities[key][id];
        delete newData.id;
        return {
          ...memo,
          [key]: {
            ...memo[key],
            [id]: update(memo[key][id], newData),
          },
        };
      }, state);
    }
    case EntitiesActions.UPDATE_ENTITY_ID: {
      const { key, schema, oldId, newId } = action.payload;
      const updatedEntity = { ...state[key][oldId], id: newId };
      return mapValues(state, (currentEntities, key) => {
        // The entities we need to update
        if (key === schema.getKey()) {
          return omit({
            ...currentEntities,
            [newId]: updatedEntity,
          }, oldId);
        }
        // No related entities, so no need to perform any update
        if ( ! schema.isRelatedTo(key)) {
          return currentEntities;
        }
        // The entities are related
        const { isParent, relatedPropName } = schema.getRelation(updatedEntity, key);
        if (isParent) {
          // TODO: The entity is a OneToOne relation
          return currentEntities;
        }
        // The entities are the 'many' part in a OneToMany relation
        return mapValues(currentEntities, (entity) => {
          if (entity[relatedPropName] !== oldId) {
            return entity;
          }
          return {
            ...entity,
            [relatedPropName]: newId,
          };
        });
      });
    }
    case EntitiesActions.DELETE_ENTITY: {
      const { key, id } = action.payload;
      return {
        ...state,
        [key]: omit(state[key], id),
      };
    }
    default:
      return state;
  }
}

export default function entities(schemas) {
  if (isEmpty(schemas)) {
    throw new Error('[INVALID SCHEMAS]');
  }
  const emptyEntities = mapValues(schemas, () => ({}));
  return (state=emptyEntities, action) => reducer(state, action);
}
<|endoftext|>


<commit_before>var uri = require('./uri.js');
var ajax = require('./ajax.js');

function oReq(){
	var self = this;

	self._retry = 0;
	self._maxRetry = 1;
}
oReq.prototype._setParam = function(o, sUri){
	var self = this;
	if(!o){
		o = {};
	}
	if(!o.data){
		o.data = {};
	}
	o.data.token = window.ajaxToken;
	o.dataType = 'json';
	if(!o.error){
		o.error = function(){
			console.log('req error times:' + self._retry + ', ' + (o.url ? o.url : 'empty'));
			if(self._retry > self._maxRetry){
				return;
			}
			setTimeout(function(){
				self._retry = self._retry + 1;
				self._send(o);
			}, 1000);
		};
	}
	o.url = uri(sUri);
};
oReq.prototype._send = function(o){
	ajax(o);
};
oReq.prototype._get = function(sUri, oParam){
	var self = this;
	self._setParam(oParam, sUri);
	oParam.method = 'GET';
	oParam.type = 'GET';
	//
	oParam.data.rnd = new Date().getTime();
	//
	self._send(oParam);
};
oReq.prototype._post = function(sUri, oParam){
	var self = this;
	self._setParam(oParam, sUri);
	oParam.method = 'POST';
	oParam.type = 'POST';
	self._send(oParam);
};
oReq.prototype._jsonp = function(sUri, oParam){
	var self = this;
	self._setParam(oParam, sUri);
	oParam.method = 'GET';
	oParam.type = 'GET';
	//
	oParam.data.rnd = new Date().getTime();
	//
	oParam.dataType = 'jsonp';
	oParam.url = uri(sUri);
	self._send(oParam);
};
function _checkArg(args){
	if(!args){
		args = [];
	}
	if(!args[0]){
		args[0] = '';
	}
	if(!args[1]){
		args[1] = {};
	}
}

exports.get = function(){
	var req = new oReq();
	_checkArg(arguments);
	req._get(arguments[0], arguments[1]);
};

exports.post = function(){
	var req = new oReq();
	_checkArg(arguments);
	req._post(arguments[0], arguments[1]);
};

exports.jsonp = function(){
	var req = new oReq();
	_checkArg(arguments);
	req._jsonp(arguments[0], arguments[1]);
};<commit_msg>feat: Request - Delete token & rnd<commit_after>var uri = require('./uri.js');
var ajax = require('./ajax.js');

function oReq(){
	var self = this;

	self._retry = 0;
	self._maxRetry = 1;
}
oReq.prototype._setParam = function(o, sUri){
	var self = this;
	if(!o){
		o = {};
	}
	if(!o.data){
		o.data = {};
	}
	o.dataType = 'json';
	if(!o.error){
		o.error = function(){
			console.log('req error times:' + self._retry + ', ' + (o.url ? o.url : 'empty'));
			if(self._retry > self._maxRetry){
				return;
			}
			setTimeout(function(){
				self._retry = self._retry + 1;
				self._send(o);
			}, 1000);
		};
	}
	o.url = uri(sUri);
};
oReq.prototype._send = function(o){
	ajax(o);
};
oReq.prototype._get = function(sUri, oParam){
	var self = this;
	self._setParam(oParam, sUri);
	oParam.method = 'GET';
	oParam.type = 'GET';
	self._send(oParam);
};
oReq.prototype._post = function(sUri, oParam){
	var self = this;
	self._setParam(oParam, sUri);
	oParam.method = 'POST';
	oParam.type = 'POST';
	self._send(oParam);
};
oReq.prototype._jsonp = function(sUri, oParam){
	var self = this;
	self._setParam(oParam, sUri);
	oParam.method = 'GET';
	oParam.type = 'GET';
	//
	oParam.data.rnd = new Date().getTime();
	//
	oParam.dataType = 'jsonp';
	oParam.url = uri(sUri);
	self._send(oParam);
};
function _checkArg(args){
	if(!args){
		args = [];
	}
	if(!args[0]){
		args[0] = '';
	}
	if(!args[1]){
		args[1] = {};
	}
}

exports.get = function(){
	var req = new oReq();
	_checkArg(arguments);
	req._get(arguments[0], arguments[1]);
};

exports.post = function(){
	var req = new oReq();
	_checkArg(arguments);
	req._post(arguments[0], arguments[1]);
};

exports.jsonp = function(){
	var req = new oReq();
	_checkArg(arguments);
	req._jsonp(arguments[0], arguments[1]);
};<|endoftext|>


<commit_before>var https = require('https');
module.exports = function (root, accessToken) {
  var cache = {};

  return function request(method, url, body, callback) {
    if (typeof body === "function" && callback === undefined) {
      callback = body;
      body = undefined;
    }
    if (!callback) return request.bind(this, accessToken, method, url, body);
    url = url.replace(":root", root);

    var json;
    var headers = {
      "User-Agent": "node.js"
    };
    if (accessToken) {
      headers["Authorization"] = "token " + accessToken;
    }
    if (body) {
      headers["Content-Type"] = "application/json";
      try { json = JSON.stringify(body); }
      catch (err) { return callback(err); }
    }
    if (method === "GET") {
      var cached = cache[url];
      if (cached) {
        headers["If-None-Match"] = cached.etag;
      }
    }
    var options = {
      hostname: "api.github.com",
      path: url,
      method: method,
      headers: headers
    };
    var req = https.request(options, function (res) {
      var response;
      var body = [];
      res.on("data", function (chunk) {
        body.push(chunk);
      });
      res.on("end", function () {
        body = Buffer.concat(body).toString();
        console.log(method, url, res.statusCode);
        console.log("Rate limit %s/%s left", res.headers['x-ratelimit-remaining'], res.headers['x-ratelimit-limit']);
        if (res.statusCode >= 400 && res.statusCode < 500) return callback();
        else if (res.statusCode === 200 && method === "GET") {
          cache[url] = {
            body: body,
            etag: res.headers.etag
          };
        }
        else if (res.statusCode === 304) {
          body = cache[url].body;
        }
        else if (res.statusCode < 200 || res.statusCode >= 300) {
          return callback(new Error("Invalid HTTP response: " + res.statusCode));
        }
        if (body) {
          try { response = JSON.parse(body); }
          catch (err) { return callback(err); }
        }
        return callback(null, response);
      });
    });
    req.end(json);
    req.on("error", callback);
  };
};
<commit_msg>Only cache HTTP responses for non-object requests<commit_after>var https = require('https');
module.exports = function (root, accessToken) {
  var cache = {};

  return function request(method, url, body, callback) {
    if (typeof body === "function" && callback === undefined) {
      callback = body;
      body = undefined;
    }
    if (!callback) return request.bind(this, accessToken, method, url, body);
    url = url.replace(":root", root);

    var json;
    var headers = {
      "User-Agent": "node.js"
    };
    if (accessToken) {
      headers["Authorization"] = "token " + accessToken;
    }
    if (body) {
      headers["Content-Type"] = "application/json";
      try { json = JSON.stringify(body); }
      catch (err) { return callback(err); }
    }
    if (method === "GET") {
      var cached = cache[url];
      if (cached) {
        headers["If-None-Match"] = cached.etag;
      }
    }
    var options = {
      hostname: "api.github.com",
      path: url,
      method: method,
      headers: headers
    };
    var req = https.request(options, function (res) {
      var response;
      var body = [];
      res.on("data", function (chunk) {
        body.push(chunk);
      });
      res.on("end", function () {
        body = Buffer.concat(body).toString();
        console.log(method, url, res.statusCode);
        console.log("Rate limit %s/%s left", res.headers['x-ratelimit-remaining'], res.headers['x-ratelimit-limit']);
        if (res.statusCode >= 400 && res.statusCode < 500) return callback();
        else if (res.statusCode === 200 && method === "GET" && /\/refs\//.test(url)) {
          cache[url] = {
            body: body,
            etag: res.headers.etag
          };
        }
        else if (res.statusCode === 304) {
          body = cache[url].body;
        }
        else if (res.statusCode < 200 || res.statusCode >= 300) {
          return callback(new Error("Invalid HTTP response: " + res.statusCode));
        }
        if (body) {
          try { response = JSON.parse(body); }
          catch (err) { return callback(err); }
        }
        return callback(null, response);
      });
    });
    req.end(json);
    req.on("error", callback);
  };
};
<|endoftext|>


<commit_before>const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const child_process = require('child_process')

/**
 * Start web service
 * @param {Object} options
 */
function runWeb(options) {
  if (!checkWebEnv(process.cwd())) {
    console.log()
    console.log(chalk.red('  Not available web environment !'))
    console.log()
    console.log(`  You should run ${chalk.blue('weexpack init')} first`)
    return
  }

  console.log()
  console.log(` => ${chalk.blue.bold('Starting web service')}`)

  install()
  startServer()
}

/**
 * Check web environment
 * @param {Strng} cwd
 */
function checkWebEnv(cwd) {
  return fs.existsSync(path.join(cwd, 'package.json'))
      && fs.existsSync(path.join(cwd, 'web'))
}

/**
 * Install npm dependencies
 */
function install() {
  console.log(`    installing npm packages ...`)
  child_process.execSync('cnpm install')
}

/**
 * Start a web server
 */
function startServer() {
  console.log(`    start server`)

  child_process.execSync('npm run build & npm run serve')

  console.log()
  console.log(` => ${chalk.green('server is running')}`)
  console.log(`    see {chalk.cyan('http://localhost:8080/web/index.html')}`)
}

module.exports = runWeb
<commit_msg>install npm package explicitly<commit_after>const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const child_process = require('child_process')

/**
 * Start web service
 * @param {Object} options
 */
function runWeb(options) {
  if (!checkWebEnv(process.cwd())) {
    console.log()
    console.log(chalk.red('  Not available web environment !'))
    console.log()
    console.log(`  You should run ${chalk.blue('weexpack init')} first`)
    return
  }

  console.log()
  console.log(` => ${chalk.blue.bold('Starting web service')}`)

  install()
  startServer()
}

/**
 * Check web environment
 * @param {Strng} cwd
 */
function checkWebEnv(cwd) {
  return fs.existsSync(path.join(cwd, 'package.json'))
      && fs.existsSync(path.join(cwd, 'web'))
}

/**
 * Install npm dependencies
 */
function install() {
  console.log(`    installing npm packages ...`)

  const deps = [
    'weex-html5',
  ]
  const devDeps = [
    'babel-core',
    'babel-loader',
    'eslint',
    'serve',
    'webpack',
    'weex-loader',
  ]

  child_process.execSync(`cnpm install ${deps.join(' ')} --save`)
  child_process.execSync(`cnpm install ${devDeps.join(' ')} --save-dev`)
}

/**
 * Start a web server
 */
function startServer() {
  console.log(`    start server`)

  child_process.execSync('npm run build & npm run serve')

  console.log()
  console.log(` => ${chalk.green('server is running')}`)
  console.log(`    see {chalk.cyan('http://localhost:8080/web/index.html')}`)
}

module.exports = runWeb
<|endoftext|>


<commit_before>'use strict'

const element = require('./decorators/element')
const include = require('./decorators/include')
const {EventsDelegation} = require('atom-utils')
const {CompositeDisposable} = require('atom')
const modules = [
  'os', 'time', 're', 'sys', 'datetime', 'random', 'django', 'json', 'urllib',
  'subprocess', 'math', 'urllib2', 'logging', 'numpy', 'threading', 'shutil',
  'hashlib', 'socket', 'collections', 'copy', 'itertools', 'traceback',
  'tempfile', 'xml', 'urlparse', 'struct', 'flask', 'StringIO', 'string',
  'optparse', 'base64', 'glob', 'csv', 'requests', 'argparse', 'functools',
  'google', 'pickle', 'ConfigParser', 'matplotlib', 'simplejson', 'south',
  'uuid', 'inspect', 'sqlite3', 'cStringIO', 'operator', 'scipy', 'codecs',
  'unittest', 'pygame', 'cgi', 'getopt', 'cPickle', 'httplib', 'pprint',
  'email', 'BeautifulSoup', 'warnings', 'PIL', 'lxml', 'gtk', 'zipfile',
  'sqlalchemy', 'PyQt4', 'multiprocessing', 'smtplib', 'Queue', 'yaml',
  'twisted', 'MySQLdb', 'select', 'getpass', 'gzip', 'imp', 'ctypes',
  'platform', 'mock', 'wx', 'fnmatch', 'mimetypes', 'fabric', 'signal',
  'pymongo', 'io', 'binascii', 'nose', 'decimal', 'pylab', 'shlex', 'commands',
  'distutils', 'textwrap', 'zlib', 'md5', 'serial', 'calendar', 'hmac',
  'jinja2', 'array', 'fcntl', 'thread', 'unicodedata', 'webbrowser',
  'dateutil', 'werkzeug', 'sublime', 'bottle', 'locale', 'pkg_resources',
  'cookielib', 'gobject', 'feedparser', 'tarfile', 'web', 'nltk', 'httplib2',
  'markdown', 'xmlrpclib', 'boto', 'zope', 'redis', 'heapq', 'ast', 'pdb',
  'Tkinter', 'bisect', 'tornado', 'weakref', 'pyramid', 'psycopg2', 'Crypto',
  'difflib', 'gc', 'HTMLParser', 'gi', 'pwd', 'doctest', 'gevent', 'atexit',
  'gettext', 'networkx', 'curses', 'contextlib', 'pandas', 'exceptions',
  'stat', 'bson', 'pytz', 'sklearn', 'importlib', 'dbus', 'BaseHTTPServer',
  'pygments', 'docutils', 'selenium', 'oauth2', 'twitter', 'scrapy', 'ssl',
  'mako', 'cherrypy', 'shelve', 'paramiko', 'tweepy', 'mechanize', 'types',
  'rospy', 'cv2', 'PySide', 'parser', 'pytest', 'celery', 'posixpath', 'sha',
  'tkFileDialog', 'asyncore', 'tkMessageBox', 'xlrd', 'webob', 'win32api',
  'SocketServer', 'fileinput', 'cv', 'transaction', 'game', 'setuptools',
  'Cookie', 'tests', 'plone', 'xbmcgui', 'code', 'pycurl', 'bz2', 'ftplib',
  'IPython', 'ImageDraw', 'zmq'
]

class KiteWrapper {
  static initClass () {
    include(this, EventsDelegation)
    return element(this, 'kite-minimap-wrapper')
  }

  static isLegible (textEditor) {
    const path = textEditor.getPath()
    return path && /\.py$/.test(path) && !atom.packages.getLoadedPackage('kite')
  }

  static handle (textEditor, minimapElement) {
    let wrapper = new this()
    wrapper.textEditor = textEditor
    wrapper.minimap = minimapElement.getModel()
    wrapper.minimapElement = minimapElement
    wrapper.wrap(minimapElement)
  }

  destroy () {
    this.subscriptions.dispose()
    this.observer.disconnect()
    delete this.minimap
    delete this.minimapElement
    delete this.textEditor
    this.remove()
  }

  unwrap () {
    this.parentNode.insertBefore(this.minimapElement, this)
    this.destroy()
  }

  wrap (minimapElement) {
    minimapElement.parentNode.insertBefore(this, minimapElement)

    this.content = document.createElement('div')
    this.appendChild(minimapElement)
    this.appendChild(this.content)

    this.observer = new window.MutationObserver(() => {
      this.style.cssText = minimapElement.style.cssText
      this.className = minimapElement.className
    })

    this.observer.observe(minimapElement, {attributes: true})

    this.minimap.getScreenHeight = function () {
      if (this.isStandAlone()) {
        if (this.height != null) {
          return this.height
        } else {
          return this.getHeight()
        }
      } else {
        return minimapElement.clientHeight
      }
    }

    this.update()
  }

  update () {
    const matches = []
    this.textEditor.scan(/(import|from)\s+(\w+)/g, (m) => {
      matches.push(m.match[2])
    })
    const links = modules.filter(m => matches.includes(m)).slice(0, 5).map(this.link)

    this.content.innerHTML = this.snippet(links.join(''))
  }

  snippet (content) {
    return `

      docs

${content}

    `
  }

  link (mod) {
    return `<li><a href="https://alpha.kite.com/docs/python/${mod}?source=minimap">${mod}</a></li>`
  }

  attachedCallback () {
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.textEditor.onDidStopChanging(() => {
      this.update()
    }))

    this.subscriptions.add(this.minimap.onDidDestroy(() => {
      this.destroy()
    }))

    this.subscriptions.add(atom.config.observe('minimap.disablePythonDocLinks', (v) => {
      if (v) { this.unwrap() }
    }))

    this.subscriptions.add(this.subscribeTo(this, '.collapser', {
      'click': () => {
        this.querySelector('.collapser').classList.toggle('collapse')
      }
    }))

    this.subscriptions.add(this.subscribeTo(this, '.icon-remove-close', {
      'click': () => {
        atom.config.set('minimap.disablePythonDocLinks', true)
      }
    }))
  }
}

module.exports = KiteWrapper.initClass()
<commit_msg>Ignore links on linux<commit_after>'use strict'

const os = require('os')
const element = require('./decorators/element')
const include = require('./decorators/include')
const {EventsDelegation} = require('atom-utils')
const {CompositeDisposable} = require('atom')
const modules = [
  'os', 'time', 're', 'sys', 'datetime', 'random', 'django', 'json', 'urllib',
  'subprocess', 'math', 'urllib2', 'logging', 'numpy', 'threading', 'shutil',
  'hashlib', 'socket', 'collections', 'copy', 'itertools', 'traceback',
  'tempfile', 'xml', 'urlparse', 'struct', 'flask', 'StringIO', 'string',
  'optparse', 'base64', 'glob', 'csv', 'requests', 'argparse', 'functools',
  'google', 'pickle', 'ConfigParser', 'matplotlib', 'simplejson', 'south',
  'uuid', 'inspect', 'sqlite3', 'cStringIO', 'operator', 'scipy', 'codecs',
  'unittest', 'pygame', 'cgi', 'getopt', 'cPickle', 'httplib', 'pprint',
  'email', 'BeautifulSoup', 'warnings', 'PIL', 'lxml', 'gtk', 'zipfile',
  'sqlalchemy', 'PyQt4', 'multiprocessing', 'smtplib', 'Queue', 'yaml',
  'twisted', 'MySQLdb', 'select', 'getpass', 'gzip', 'imp', 'ctypes',
  'platform', 'mock', 'wx', 'fnmatch', 'mimetypes', 'fabric', 'signal',
  'pymongo', 'io', 'binascii', 'nose', 'decimal', 'pylab', 'shlex', 'commands',
  'distutils', 'textwrap', 'zlib', 'md5', 'serial', 'calendar', 'hmac',
  'jinja2', 'array', 'fcntl', 'thread', 'unicodedata', 'webbrowser',
  'dateutil', 'werkzeug', 'sublime', 'bottle', 'locale', 'pkg_resources',
  'cookielib', 'gobject', 'feedparser', 'tarfile', 'web', 'nltk', 'httplib2',
  'markdown', 'xmlrpclib', 'boto', 'zope', 'redis', 'heapq', 'ast', 'pdb',
  'Tkinter', 'bisect', 'tornado', 'weakref', 'pyramid', 'psycopg2', 'Crypto',
  'difflib', 'gc', 'HTMLParser', 'gi', 'pwd', 'doctest', 'gevent', 'atexit',
  'gettext', 'networkx', 'curses', 'contextlib', 'pandas', 'exceptions',
  'stat', 'bson', 'pytz', 'sklearn', 'importlib', 'dbus', 'BaseHTTPServer',
  'pygments', 'docutils', 'selenium', 'oauth2', 'twitter', 'scrapy', 'ssl',
  'mako', 'cherrypy', 'shelve', 'paramiko', 'tweepy', 'mechanize', 'types',
  'rospy', 'cv2', 'PySide', 'parser', 'pytest', 'celery', 'posixpath', 'sha',
  'tkFileDialog', 'asyncore', 'tkMessageBox', 'xlrd', 'webob', 'win32api',
  'SocketServer', 'fileinput', 'cv', 'transaction', 'game', 'setuptools',
  'Cookie', 'tests', 'plone', 'xbmcgui', 'code', 'pycurl', 'bz2', 'ftplib',
  'IPython', 'ImageDraw', 'zmq'
]

class KiteWrapper {
  static initClass () {
    include(this, EventsDelegation)
    return element(this, 'kite-minimap-wrapper')
  }

  static isLegible (textEditor) {
    const path = textEditor.getPath()
    return path && /\.py$/.test(path) && os.platform() !== 'linux' && !atom.packages.getLoadedPackage('kite')
  }

  static handle (textEditor, minimapElement) {
    let wrapper = new this()
    wrapper.textEditor = textEditor
    wrapper.minimap = minimapElement.getModel()
    wrapper.minimapElement = minimapElement
    wrapper.wrap(minimapElement)
  }

  destroy () {
    this.subscriptions.dispose()
    this.observer.disconnect()
    delete this.minimap
    delete this.minimapElement
    delete this.textEditor
    this.remove()
  }

  unwrap () {
    this.parentNode.insertBefore(this.minimapElement, this)
    this.destroy()
  }

  wrap (minimapElement) {
    minimapElement.parentNode.insertBefore(this, minimapElement)

    this.content = document.createElement('div')
    this.appendChild(minimapElement)
    this.appendChild(this.content)

    this.observer = new window.MutationObserver(() => {
      this.style.cssText = minimapElement.style.cssText
      this.className = minimapElement.className
    })

    this.observer.observe(minimapElement, {attributes: true})

    this.minimap.getScreenHeight = function () {
      if (this.isStandAlone()) {
        if (this.height != null) {
          return this.height
        } else {
          return this.getHeight()
        }
      } else {
        return minimapElement.clientHeight
      }
    }

    this.update()
  }

  update () {
    const matches = []
    this.textEditor.scan(/(import|from)\s+(\w+)/g, (m) => {
      matches.push(m.match[2])
    })
    const links = modules.filter(m => matches.includes(m)).slice(0, 5).map(this.link)

    this.content.innerHTML = this.snippet(links.join(''))
  }

  snippet (content) {
    return `

      docs

${content}

    `
  }

  link (mod) {
    return `<li><a href="https://alpha.kite.com/docs/python/${mod}?source=minimap">${mod}</a></li>`
  }

  attachedCallback () {
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.textEditor.onDidStopChanging(() => {
      this.update()
    }))

    this.subscriptions.add(this.minimap.onDidDestroy(() => {
      this.destroy()
    }))

    this.subscriptions.add(atom.config.observe('minimap.disablePythonDocLinks', (v) => {
      if (v) { this.unwrap() }
    }))

    this.subscriptions.add(this.subscribeTo(this, '.collapser', {
      'click': () => {
        this.querySelector('.collapser').classList.toggle('collapse')
      }
    }))

    this.subscriptions.add(this.subscribeTo(this, '.icon-remove-close', {
      'click': () => {
        atom.config.set('minimap.disablePythonDocLinks', true)
      }
    }))
  }
}

module.exports = KiteWrapper.initClass()
<|endoftext|>


<commit_before>var EventEmitter = require("events").EventEmitter,
    express = require("express"),
    prop = require("propertize"),
    later = require(".."),
    forward = require("./forward-event");

/**
 * HTTP later server object.
 * @constructor
 * @augments {EventEmitter}
 * @param {object} [opts]
 * @param {string[]} [opts.methods]
 * @param {string[]} [opts.hosts]
 * @param {string[]} [opts.paths]
 * @param {number} [opts.port]
 */
function LaterServer(opts) {
    EventEmitter.call(this);

    prop.readonly(this, "express", express());
    prop.readonly(this, "servers", []);

    // forward Express app events to this object
    forward("connection", this.express, this);
    forward("error", this.express, this);
    forward("request", this.express, this);
    forward("checkContinue", this.express, this);
    forward("connect", this.express, this);
    forward("upgrade", this.express, this);
    forward("clientError", this.express, this);

    // setup Express app
    this.express.all("*", this.createMiddleware(opts));
}

LaterServer.prototype = Object.create(EventEmitter.prototype);
LaterServer.prototype.constructor = LaterServer;

/**
 * Create a server object.
 * @param {object} [opts]
 * @param {string[]} [opts.methods]
 * @param {string[]} [opts.hosts]
 * @param {string[]} [opts.paths]
 * @param {number} [opts.port]
 */
LaterServer.create = function(opts) {
    return new LaterServer(opts);
};

/**
 * Stop the server from accepting new conections.
 * @param {function} [callback]
 */
LaterServer.prototype.close = function(callback) {
    var later = this,
        closing = this.servers.splice(0, this.servers.length);

    // add listener
    if (callback) this.on("close", callback);

    // for each closing server
    closing.forEach(function(server) {
        // close the server
        server.close(function() {
            // remove server from list
            var index = closing.indexOf(server);
            if (index >= 0) {
                closing.splice(index, 1);

                // emit close event once all servers are closed
                if (closing.length === 0) {
                    later.emit("close");
                }
            }
        });
    });
};

/**
 * Return the bound addresses.
 * @returns {object}
 */
LaterServer.prototype.address = function() {
    return this.servers.map(function(server) {
        return server.address();
    });
};

/**
 * Bind and listen for incoming requests on the specified host and port.
 * @param {number} port
 * @param {string} [hostname]
 * @param {number} [backlog]
 * @param {function} [callback]
 * @returns {Server}
 */
LaterServer.prototype.listen = function(port, hostname, backlog, callback) {
    var server;

    // extend callback to pass server address
    if (typeof arguments[arguments.length-1] === "function") {
        callback = arguments[arguments.length-1];
        arguments[arguments.length-1] = function() {
            callback(server.address());
        };
    }

    // create new server
    server = this.express.listen.apply(this.express, arguments);
    this.servers.push(server);
    return server;
};

/**
 * Create Express middleware for this server.
 * @param {object} [opts]
 * @returns {function}
 */
LaterServer.prototype.createMiddleware = function(opts) {
    opts = opts || {};

    return function(req, res, next) {
        var pathOk;

        // validate request against allowed paths
        pathOk = !opts.paths || opts.paths.some(function(path) {
            return req.path.substr(0, path.length) === path;
        });

        // reject path mismatch with 404
        if (!pathOk) {
            res.writeHead(404, {"Content-Type": "text/plain"});
            res.end("Not Found");
        }

        // reject method mismatch with 405
        else if ((opts.methods || ["POST"]).indexOf(req.method) < 0) {
            res.writeHead(405, {"Content-Type": "text/plain"});
            res.end("Method Not Allowed");
        }

        // accept anything else
        else {
            res.writeHead(202);
            res.end();
        }
    };
};

/** export LaterServer class */
module.exports = LaterServer;
<commit_msg>refactor options out of middleware<commit_after>var EventEmitter = require("events").EventEmitter,
    express = require("express"),
    prop = require("propertize"),
    later = require(".."),
    forward = require("./forward-event");

/**
 * HTTP later server object.
 * @constructor
 * @augments {EventEmitter}
 * @param {object} [opts]
 * @param {string[]} [opts.methods]
 * @param {string[]} [opts.hosts]
 * @param {string[]} [opts.paths]
 * @param {number} [opts.port]
 */
function LaterServer(opts) {
    EventEmitter.call(this);

    prop.internal(this, "servers", []);

    /**
     * @name LaterServer#methods
     * @type {string[]}
     * @readonly
     */
    prop.readonly(this, "methods", opts.methods || ["POST"]);

    /**
     * @name LaterServer#paths
     * @type {string[]}
     * @readonly
     */
    prop.readonly(this, "paths", opts.paths || []);

    /**
     * @name LaterServer#express
     * @type {function}
     * @readonly
     */
    prop.readonly(this, "express", express());

    // forward Express app events to this object
    forward("connection", this.express, this);
    forward("error", this.express, this);
    forward("request", this.express, this);
    forward("checkContinue", this.express, this);
    forward("connect", this.express, this);
    forward("upgrade", this.express, this);
    forward("clientError", this.express, this);

    // setup Express app
    this.express.all("*", this.createMiddleware());
}

LaterServer.prototype = Object.create(EventEmitter.prototype);
LaterServer.prototype.constructor = LaterServer;

/**
 * Create a server object.
 * @param {object} [opts]
 * @param {string[]} [opts.methods]
 * @param {string[]} [opts.hosts]
 * @param {string[]} [opts.paths]
 * @param {number} [opts.port]
 */
LaterServer.create = function(opts) {
    return new LaterServer(opts);
};

/**
 * Return true if the method is allowed.
 * @param {string} method
 * @returns {boolean}
 */
LaterServer.prototype.methodAllowed = function(method) {
    // if no methods are defined, allow any method
    if (this.methods.length === 0) return true;

    // check if any of the methods match
    return this.methods.indexOf(method) >= 0;
};

/**
 * Return true if the path is acceptable.
 * @param {string} path
 * @returns {boolean}
 */
LaterServer.prototype.pathAcceptable = function(path) {
    // if no paths are defined, accept all paths
    if (this.paths.length === 0) return true;

    // check if any of the paths match
    return this.paths.some(function(base) {
        return path.substr(0, base.length) === base;
    });
};

/**
 * Stop the server from accepting new conections.
 * @param {function} [callback]
 */
LaterServer.prototype.close = function(callback) {
    var later = this,
        closing = this.servers.splice(0, this.servers.length);

    // add listener
    if (callback) this.on("close", callback);

    // for each closing server
    closing.forEach(function(server) {
        // close the server
        server.close(function() {
            // remove server from list
            var index = closing.indexOf(server);
            if (index >= 0) {
                closing.splice(index, 1);

                // emit close event once all servers are closed
                if (closing.length === 0) {
                    later.emit("close");
                }
            }
        });
    });
};

/**
 * Return the bound addresses.
 * @returns {object}
 */
LaterServer.prototype.address = function() {
    return this.servers.map(function(server) {
        return server.address();
    });
};

/**
 * Bind and listen for incoming requests on the specified host and port.
 * @param {number} port
 * @param {string} [hostname]
 * @param {number} [backlog]
 * @param {function} [callback]
 * @returns {Server}
 */
LaterServer.prototype.listen = function(port, hostname, backlog, callback) {
    var server;

    // extend callback to pass server address
    if (typeof arguments[arguments.length-1] === "function") {
        callback = arguments[arguments.length-1];
        arguments[arguments.length-1] = function() {
            callback(server.address());
        };
    }

    // create new server
    server = this.express.listen.apply(this.express, arguments);
    this.servers.push(server);
    return server;
};

/**
 * Create Express middleware for this server.
 * @returns {function}
 */
LaterServer.prototype.createMiddleware = function() {
    var later = this;

    return function(req, res, next) {
        if (!later.pathAcceptable(req.path)) {
            res.writeHead(404, {"Content-Type": "text/plain"});
            res.end("Not Found");
        }

        else if (!later.methodAllowed(req.method)) {
            res.writeHead(405, {
                "Allow": later.methods.join(","),
                "Content-Type": "text/plain"
            });
            res.end("Method Not Allowed");
        }

        // accept anything else
        else {
            res.writeHead(202);
            res.end();
        }
    };
};

/** export LaterServer class */
module.exports = LaterServer;
<|endoftext|>