JSPM

@poppinss/mrm-core

1.0.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • 0
    • Score
      100M100P100Q26497F
    • License MIT

    Utilities to make tasks for Mrm

    Package Exports

    • @poppinss/mrm-core
    • @poppinss/mrm-core/src/index.js

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@poppinss/mrm-core) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    mrm-core

    npm

    Utilities to write codemods for config files (JSON, YAML, INI, Markdown, etc.). Can be used to make tasks for Mrm.

    Example

    Add ESLint to your project:

    const { json, lines, packageJson, install } = require('mrm-core');
    
    module.exports = function(config) {
      const preset = config('preset', 'tamia');
      const packages = ['eslint', `eslint-config-${preset}`];
    
      // .eslintrc
      const eslintrc = json('.eslintrc');
      if (!eslintrc.get('extends').startsWith(preset)) {
        eslintrc.set('extends', preset).save();
      }
    
      // .eslintignore
      lines('.eslintignore')
        .add('node_modules')
        .save();
    
      // package.json
      const pkg = packageJson()
        .setScript('lint', 'eslint . --fix')
        .setScript('pretest', 'npm run line')
        .save();
    
      // Install dependencies
      install(packages);
    };
    module.exports.description = 'Adds ESLint with a custom preset';

    Read more in the docs, and this task is already included by default.

    You can find more examples in my dotfiles repository.

    You don’t have to use mrm-core with mrm, you can run this tasks from your own code:

    const get = require('lodash/get');
    const addEslint = require('./tasks/eslint');
    const config = {
      preset: 'airbnb'
    };
    const getConfig = (prop, defaultValue) =>
      get(config, prop, defaultValue);
    addEslint(getConfig);

    Installation

    npm install mrm-core

    API

    Work with files

    • Do not overwrite original files, unless you want to.
    • All functions (except getters) can be chained.
    • save() will create file if it doesn’t exist or update it with new data.
    • save() will write file to disk only if the new content is different from the original file.
    • save() will try to keep formatting (indentation, end of file new line) of the original file or use style from EditorConfig.

    JSON

    API:

    const { json } = require('mrm-core');
    const file = json('file name', { default: 'values' });
    file.exists(); // File exists?
    file.get(); // Return everything
    file.get('key.subkey', 'default value'); // Return value with given address
    file.set('key.subkey', 'value'); // Set value by given address
    file.set({ key: value }); // Replace JSON with given object
    file.unset('key.subkey'); // Remove value by given address
    file.merge({ key: value }); // Merge JSON with given object
    file.save(); // Save file
    file.delete(); // Delete file

    Example:

    json('.eslintrc')
      .merge({
        extends: 'eslint-config-recommended'
      })
      .save();

    YAML

    API:

    const { yaml } = require('mrm-core');
    const file = yaml(
      'file name', // File name
      { default: 'values' }, // Default value
      { version: '1.2' } // Options
    );
    file.exists(); // File exists?
    file.get(); // Return everything
    file.get('key.subkey', 'default value'); // Return value with given address
    file.set('key.subkey', 'value'); // Set value by given address
    file.set({ key: value }); // Replace JSON with given object
    file.unset('key.subkey'); // Remove value by given address
    file.merge({ key: value }); // Merge JSON with given object
    file.save(); // Save file
    file.delete(); // Delete file

    Example:

    yaml('.travis.yml')
      .set('language', 'node_js')
      .set('node_js', [4, 6])
      .save();

    INI

    API:

    const { ini } = require('mrm-core');
    const file = ini('file name', 'comment');
    file.exists(); // File exists?
    file.get(); // Return everything
    file.get('section name'); // Return section value
    file.set('section name', { key: value }); // Set section value
    file.unset('section name'); // Remove section
    file.save(); // Save file
    file.save({ withSpaces: false }); // Disable spaces around =
    file.delete(); // Delete file

    Example:

    const { ini } = require('mrm-core');
    ini('.editorconfig', 'editorconfig.org')
      .set('_global', { root: true })
      .set('*', {
        indent_style: 'tab',
        end_of_line: 'lf'
      })
      .save();

    Result:

    # editorconfig.org
    root = true
    
    [*]
    indent_style = tab
    end_of_line = lf

    New line separated text files

    API:

    const { lines } = require('mrm-core');
    const file = lines('file name', ['default', 'values']);
    file.exists(); // File exists?
    file.get(); // Return everything
    file.set(['line 1', 'line 2', 'line 3']); // Set file lines, overwrite existing
    file.add('new'); // Add new line
    file.add(['new', 'lines']); // Add multiple news lines
    file.remove('new'); // Remove line
    file.remove(['new', 'lines']); // Remove multiple lines
    file.save(); // Save file
    file.delete(); // Delete file

    Example:

    lines('.eslintignore')
      .add('node_modules')
      .save();

    Markdown

    Note: use template function to create Markdown files.

    API:

    const { markdown } = require('mrm-core');
    const file = markdown('file name');
    file.exists(); // File exists?
    file.get(); // Return file content
    // Add a badge at the beginning of the file (below header)
    file.addBadge('image URL', 'link URL', 'alt text');
    // Remove a badge when the predicate function returns true
    file.removeBadge(({ imageUrl, linkUrl, altText }) =>
      imageUrl.startsWith('https://travis-ci.org')
    );
    file.save(); // Save file
    file.delete(); // Delete file

    Example:

    const name = 'pizza';
    markdown('Readme.md')
      .addBadge(
        `https://travis-ci.org/${config('github')}/${name}.svg`,
        `https://travis-ci.org/${config('github')}/${name}`,
        'Build Status'
      )
      .save();

    Plain text templates

    Templates use ECMAScript template literals syntax.

    API:

    const { template } = require('mrm-core');
    const file = template('file name', 'template file name');
    file.exists(); // File exists?
    file.get(); // Return file content
    file.apply({ key: 'value' }); // Replace template tags with given values
    file.save(); // Save file
    file.delete(); // Delete file

    Example:

    template('License.md', path.join(__dirname, 'License.md'))
      .apply(config(), {
        year: new Date().getFullYear()
      })
      .save();

    Template:

    The MIT License
    ===============
    
    Copyright ${year} ${name} (${url}), contributors
    
    Permission is hereby granted, free of charge, to any person obtaining...

    Special files

    package.json

    API:

    const { packageJson } = require('mrm-core');
    const file = packageJson({ default: 'values' });
    file.exists(); // File exists?
    file.get(); // Return everything
    file.getScript('test'); // Return script
    file.getScript('test', 'eslint'); // Return a subcommand of a script
    file.setScript('test', 'eslint --fix'); // Replace a script with a command: a -> b
    file.appendScript('test', 'eslint --fix'); // Append command to a script: a -> a && b
    file.prependScript('test', 'eslint --fix'); // Prepend a script with a command: a -> b && a
    file.removeScript('test'); // Remove script
    file.removeScript(/^mocha|ava$/); // Remove all scripts that match a regexp
    file.removeScript('test', /b/); // Remove subcommands from a script: a && b -> a
    file.save(); // Save file
    file.delete(); // Delete file
    // All methods of json() work too

    Note: subcommand is a command between && in an npm script. For example, prettier --write '**/*.js' && eslint . --fix has two subcommands: prettier… and eslint….

    Example:

    packageJson()
      .appendScript('lint', 'eslint . --ext .js --fix')
      .save();

    File system helpers

    const { copyFiles, deleteFiles, makeDirs } = require('mrm-core');
    copyFiles('source dir', 'file name'); // Copy file
    copyFiles('source dir', ['file name 1', 'file name 2']); // Copy files
    copyFiles('source dir', 'file name', { overwrite: false }); // Do not overwrite
    deleteFiles('file name 1'); // Delete file or folder
    deleteFiles(['file name 1', 'folder name 1']); // Delete files or folders
    makeDirs('dir name'); // Create folder
    makeDirs(['dir name 1', 'dir name 2']); // Create folders

    Install and uninstall npm, Yarn, or pnpm packages

    Installs npm package(s) and saves them to package.json if they aren’t installed yet or not satisfying range.

    const { install } = require('mrm-core');
    install('eslint'); // Install to devDependencies
    install(['tamia', 'lodash'], { dev: false }); // Install to dependencies
    install({ lodash: '^4.17.3' }); // Install particular version
    install(['lodash'], {
      versions: { lodash: '^4.17.3', other: '1.0.0' }
    }); // Install particular version
    install(['github/repo']); // Install non-registry package without version

    Note: Works with all semver ranges, like 1.2.3, ^1.2.0 or >=2.

    Uninstalls npm package(s) and removes them from package.json:

    const { uninstall } = require('mrm-core');
    uninstall('eslint'); // Uninstall from devDependencies
    uninstall(['tamia', 'lodash'], { dev: false }); // Uninstall from dependencies

    To use Yarn pass yarn: true:

    const { install, uninstall } = require('mrm-core');
    
    uninstall(['eslint'], { yarn: true });
    install(['standard'], { yarn: true });

    With Yarn Berry, pass yarnBerry: true and for pnpm, pass pnpm: true.

    Utilities

    Infers style (indentation, new line at the end of file) from a source code or reads from the .editorconfig file.

    const {
      inferStyle,
      getStyleForFile,
      getIndent,
      format
    } = require('mrm-core');
    inferStyle('for (;;) {\n  alert(1);\n}\n');
    // => { insert_final_newline: true, indent_style: 'space', indent_size: 2 }
    getStyleForFile('test.js');
    // => { insert_final_newline: false, indent_style: 'tab', indent_size: 'tab' }
    getIndent({ indent_style: 'space', indent_size: 2 });
    // => '  '
    format('alert(1)\n', { insert_final_newline: false });
    // => 'alert(1)'
    // Only insert_final_newline is supported

    Get file extensions list from a command like eslint . --fix --ext .js,.jsx:

    const { getExtsFromCommand } = require('mrm-core');
    getExtsFromCommand(`eslint . --fix --ext .js,.jsx`, 'ext');
    // => ['js', 'jsx']
    getExtsFromCommand(`prettier --write '**/*.js'`);
    // => ['js']

    Custom error class: MrmError

    Use this class to notify user about expected errors in your tasks. It will be printed without a stack trace and will abort task.

    const { MrmError } = require('mrm-core');
    if (!fs.existsSync('.travis.yml')) {
      throw new MrmError('Run travis task first');
    }

    Changelog

    The changelog can be found on the Releases page.

    Contributing

    Everyone is welcome to contribute. Please take a moment to review the contributing guidelines.

    Authors and license

    Artem Sapegin and contributors.

    MIT License, see the included License.md file.