Ninja Power Manifesto

    narrange

    1.0.5 • Public • Published

    NArrange

    NArrange is a .NET code beautifier that automatically organizes code members and elements within .NET classes.

    NArrange executes a Windows .exe executable (as a child process) and thus only works on a Windows environment.

    Install

    Install as a (dev) package dependency:

    npm install narrange -D

    Quick start

    From your node.js script, execute narrange.exe in a child process

    const { createNArrange } = require("narrange");
    const path = require("path");
     
    const { narrange, ctx } = createNArrange({
      srcPath: path.join(__dirname, "src/apps/mango"),
      configFilePath: path.join(__dirname, "config/NArrange.xml")
      // set debug mode
      // debugOn: true
    });
     
    console.log(ctx);
     
    narrange();

    Note that the factory method createNArrange returns both narrange and a ctx context object. Look at the ctx object to ensure you have configured narrange correctly.

    During experimentation, pass debugOn: true as an option to createNArrange

    Pre-commit hooks

    You can use this recipe to integrate NArrange with git hooks, such as pre-commit hooks:

    • Setup git hooks via husky
    • Create node script to trigger on hook

    Setup hooks

    Install and setup husky

    Add the following to your package.json file (or create a new one using npm init)

    {
      "devDependencies": {
        "narrange": "~1.0.0"
        "husky": "~1.3.1"
      },
      "husky": {
        "hooks": {
          "pre-commit": "node format-csharp.js"
        }
      }
    }

    Run npm install from your Terminal to install dependencies: husky and narrange

    Create node script

    Create a Node script format-csharp.js that runs narrange.exe on your source files using a config file with your specific preferences.

    Assuming we put the script in a /scripts folder in the project root

    const { createNArrange } = require("narrange");
    const path = require("path");
     
    const rootPath = path.join(__dirname, "../");
    const srcPath = path.join(rootPath, "Areas")
    const configFilePath = path.join(rootPath, "config/NArrange.xml")
     
    const { narrange } = createNArrange({
      srcPath
      configFilePath
    });
     
    narrange();

    Tabs configuration

    In case you want to convert spaces to tabs, you can use one of the included configuration files

    • config/Tabs4.xml converts 4 spaces to 1 tab
    • config/Tabs2.xml converts 2 spaces to 1 tab

    Assuming we put the script in a /scripts folder in the project root

    const path = require("path");
    const rootPath = path.join(__dirname, "../");
    const narrangeHomePath = path.join(rootPath, "node_modules/narrange");
    const narrangeConfigPath = path.join(narrangeHomePath, "config");
    // const narrangeLibPath = path.join(narrangeHomePath, "lib");
     
    const configFilePath = path.join(narrangeConfigPath, "Tabs4.xml")s

    Formatting

    To create your own formatting rules, by specifying your own rules in the <Formatting> section on the config file. Use any of the files included in config or lib folders of this package.

    <Formatting>
        <Tabs Style="Tabs" SpacesPerTab="2"/>
        <ClosingComments Enabled="false" Format="End $(ElementType) $(Name)"/>
        <Regions Style="NoDirective" />
        <Usings MoveTo="Namespace"/>
        <LineSpacing RemoveConsecutiveBlankLines="true" />
    </Formatting>

    Note that you can use the narrange-config.exe to edit a configuration file using a GUI, which ensures you can only populate it with valid values.

    Simple tabs formatting configuration

    Simple configuration to force 2 spaces to be converted to a tab:

    const { narrange } = createNArrange({
      srcPath: path.join(__dirname, "src/apps/mango"),
      tabs: 4 // use instead of configFilePath to select built in Tabs config file
    });
    narrange();

    createNArrange

    The function createNArrange creates a child process which executes the narrange.exe executable. createNArrange accepts the following options:

    • onError custom stderr handler function
    • onOut custom stdout handler function
    • createMainHandler factory method to create main handler
    • createExitHandler factory method to create process exit handler
    • createWriters factory method to create writers (error, info, debug methods)
    • createCommand factory method to create the command to execute in the child process
    • exitHandler process exit handler function (takes precedence over factory)
    • mainHandler main handler function (takes precedence over factory)
    • srcPath path to input folder for narrange (location folder of source files to process)
    • configFilePath path to narrange config file
    • exePath path to narrange exe to override version available in this module
    • tabs spaces count to tabs used in formatting (used to select built in Tabs config file) - 2 or 4
    • debugOn turn debug mode on or off (default: false)

    Note that all these options are optional. If any option is left out, a default value is used.

    Custom narrange setup example :

    const { createNArrange } = require("narrange");
    const path = require("path");
     
    const createMainHandler = (opts = {}) => {
      return (err, stdout, stderr) => {
        // ..
        if (err) {
          opts.onError(err);
        }
      };
    };
     
    const onError = (err) {
      console.error(err);
    }
     
    const { narrange } = createNArrange({
      srcPath: path.join(__dirname, "src/apps/mango"),
      configFilePath: path.join(__dirname, "config/NArrange.xml"),
      createMainHandler,
      onOut,
      onError,
      // tabs: 2 // use instead of configFilePath to select built in Tabs config file
    });
    narrange();

    Exports

    narrange exports the following "building blocks":

    • exitHandler function
    • mainHandler function
    • createMainHandler factory function
    • createExitHandler factory function
    • createWriters function to create info, error, and debug functions
    • defaults config object
    • paths config object

    This should make it easy to build a custom narrange solution to suit your needs.

    Full script example

    The following example uses minimist to parse process args passed from shell.

    const path = require("path");
    const minimist = require('minimist');
    const { createNArrange } = require("narrange");
    const processArgs = process.argv.slice(2);
    const opts = {
      alias: {
        h: 'help',
        s: 'src',
        t: 'tabs'
      }
    };
     
    // args is an object, with key for each named argument
    const args = minimist(processArgs, opts);
    const defaults = {
      srcFolder: "./",
      tabs: 4
    }
    if (args.help) {
      console.log(`
    format-cs
    ---------
      -s src folder (default: ./ )
      -t spaces per tab (default: 4)
    `)
      process.exit(0);
    }
    const srcFolder = args.src || defaults.srcFolders;
    const tabs = args.tabs || defaults.tabs;
    const rootPath = path.join(__dirname, "..");
    const srcPath = path.join(rootPath, srcFolder),
     
    createNArrange({
      srcPath,
      tabs
    });

    Tests

    You can run some basic tests using jest

    $ npm test

    Note that the executable narrange.exe can only be executed on a Windows (perhaps also using Mono?) platform.

    More resources

    Recipes

    gits: PowerShell - Recurse Project

    Format-Document PowerShell function which leverages Recurse-Project and automates calling into Visual Studio’s Format Document command.

    function Format-Document {
      param(
        [parameter(ValueFromPipelineByPropertyName = $true)]
        [string[]]$ProjectName
      )
      Process {
        $ProjectName | %{
          Recurse-Project -ProjectName $_ -Action
          {
            param($item)
            if($item.Type -eq 'Folder' -or !$item.Language)
            {
              return
            }
            $win = $item.ProjectItem.Open('{7651A701-06E5-11D1-8EBD-00A0C90F26EA}')
            if ($win)
            {
              Write-Host "Processing `"$($item.ProjectItem.Name)`"" [System.Threading.Thread]::Sleep(100) $win.Activate() $item.ProjectItem.Document.DTE.ExecuteCommand('Edit.FormatDocument') $item.ProjectItem.Document.DTE.ExecuteCommand('Edit.RemoveAndSort') $win.Close(1)
            }
          }
        }
      }
    }

    Format-Document can be configured for Visual Studio and used to run your existing Format Document command on a subset of project files, using recurse project to iterate and select the files to be processed.

    Extensions

    More docs

    See [./Format-CSharp.md] for more details on using narrange directly.

    License

    See NArrange license terms

    Install

    npm i narrange

    DownloadsWeekly Downloads

    0

    Version

    1.0.5

    License

    ISC

    Unpacked Size

    652 kB

    Total Files

    21

    Last publish

    Collaborators

    • kmandrup