<commit_before>import { join } from 'path'
import { sync as symlinkSync } from 'symlink-or-copy'
import mkdirp from 'mkdirp'

import { isInitialized, filter, map, forEach, isFile, pluck, log, separator, isLink } from '../util'

export const plugin = function link (program, config, directory) {
  program.command('link')
    .description('Link packages that depend upon each other')
    .action(() => action(config, directory))
}

function action (config, directory) {
  isInitialized(config, 'link')

  if (config.packages.length === 0) {
    return log('no managed packages to symlink')
  }

  const packages = filter(map(config.packages, getPackage(directory)), Boolean)
  const packageNames = map(packages, pluck('name'))

  const findPackagesToSymlink = getPackagesToSymlink(packageNames)

  forEach(packages, function (pkg, index) {
    const { name, dependencies = false, devDependencies = false } = pkg

    // exit early if there are not dependencies to analyze
    if (!dependencies && !devDependencies) return

    const packageNamesToSymlink = findPackagesToSymlink(dependencies)
      .concat(findPackagesToSymlink(devDependencies))
      .map(toManagedNames(packageNames, config.packages))

    log(separator(name))

    if (packageNamesToSymlink.length === 0) {
      log('nothing to symlink to')
      return log(separator())
    }

    log('symlinking packages for ' + name, '...')

    symlink(packageNamesToSymlink, config.packages[index], directory)

    log(separator())
  })
}

function symlink (packagesToSymlink, symlinkToName, workingDir) {
  const nodeDir = join(workingDir, symlinkToName, 'node_modules')

  packagesToSymlink.forEach(function (pkg) {
    const srcDir = join(workingDir, pkg)
    const srcName = require(join(srcDir, 'package.json')).name
    const destinationDir = join(nodeDir, pkg)

    if (isLink(destinationDir)) {
      return log(symlinkToName, 'already exists...')
    }

    mkdirp(nodeDir, function (err) {
      if (err) throw err

      log('Symlinking ' + srcName + '...')

      if (isScoped(srcName)) {
        const [scope] = srcName.split('/')

        mkdirp(join(nodeDir, scope), function (err) {
          if (err) throw err

          symlinkSync(srcDir, join(destinationDir, scope))
        })
      } else {
        symlinkSync(srcDir, destinationDir)
      }
    })
  })
}

function isScoped (name) {
  return name[0] === '@' && name.split('/').length === 2
}

function toManagedNames (packageNames, packages) {
  return function (npmName) {
    return packages[packageNames.indexOf(npmName)]
  }
}

function getPackage (workingDir) {
  return function (packageName) {
    const packagejson = join(workingDir, packageName, 'package.json')
<commit_msg>fix(northbrook): fix linking scoped packages<commit_after>import { join } from 'path'
import { sync as symlinkSync } from 'symlink-or-copy'
import mkdirp from 'mkdirp'

import { isInitialized, filter, map, forEach, isFile, pluck, log, separator, isLink } from '../util'

export const plugin = function link (program, config, directory) {
  program.command('link')
    .description('Link packages that depend upon each other')
    .action(() => action(config, directory))
}

function action (config, directory) {
  isInitialized(config, 'link')

  if (config.packages.length === 0) {
    return log('no managed packages to symlink')
  }

  const packages = filter(map(config.packages, getPackage(directory)), Boolean)
  const packageNames = map(packages, pluck('name'))

  const findPackagesToSymlink = getPackagesToSymlink(packageNames)

  forEach(packages, function (pkg, index) {
    const { name, dependencies = false, devDependencies = false } = pkg

    // exit early if there are not dependencies to analyze
    if (!dependencies && !devDependencies) return

    const packageNamesToSymlink = findPackagesToSymlink(dependencies)
      .concat(findPackagesToSymlink(devDependencies))
      .map(toManagedNames(packageNames, config.packages))

    log(separator(name))

    if (packageNamesToSymlink.length === 0) {
      log('nothing to symlink to')
      return log(separator())
    }

    log('symlinking packages for ' + name, '...')

    symlink(packageNamesToSymlink, config.packages[index], directory)

    log(separator())
  })
}

function symlink (packagesToSymlink, symlinkToName, workingDir) {
  const nodeDir = join(workingDir, symlinkToName, 'node_modules')

  packagesToSymlink.forEach(function (pkg) {
    const srcDir = join(workingDir, pkg)
    const srcName = require(join(srcDir, 'package.json')).name
    const destinationDir = join(nodeDir, pkg)

    if (isLink(destinationDir)) {
      return log(symlinkToName, 'already exists...')
    }

    mkdirp(nodeDir, function (err) {
      if (err) throw err

      log('Symlinking ' + srcName + '...')

      if (isScoped(srcName)) {
        const [scope] = srcName.split('/')

        mkdirp(join(nodeDir, scope), function (err) {
          if (err) throw err

          symlinkSync(srcDir, join(nodeDir, scope))
        })
      } else {
        symlinkSync(srcDir, destinationDir)
      }
    })
  })
}

function isScoped (name) {
  return name[0] === '@' && name.split('/').length === 2
}

function toManagedNames (packageNames, packages) {
  return function (npmName) {
    return packages[packageNames.indexOf(npmName)]
  }
}

function getPackage (workingDir) {
  return function (packageName) {
    const packagejson = join(workingDir, packageName, 'package.json')

{'fraction_non_alphanumeric': 0.1261904761904762, 'fraction_numerical': 0.0014652014652014652, 'mean_word_length': 3.7777777777777777, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1956336', 'n_tokens_mistral': 1679, 'n_tokens_neox': 1607, 'n_words': 414}