cross-path-sort

1.0.0 • Public • Published

cross-path-sort

MIT license npm version Build Status Coverage Status

Cross-platform non-destructive file path sorting function.

Pass in an array of path strings or objects with a property whose value is path string. Get a new array with the same elements, sorted in a more intuitive way than with a simple sort:

  • You can use shallowFirst/deepFirst options to separate the content of a directory from the content of its subdirectories.
simple sort vs this function with the shallowFirst option

one.js                  one.js
test/one_spec.js        two.js
test/two_spec.js        test/one_spec.js
two.js                  test/two_spec.js
  • Different types of paths (relative, absolute, home, UNC, namespaced...) in the same array are always separated. You can change the default order of types.
simple sort vs this function on Windows

api.js                  api.js
C:\util\hash.js         engine.js
engine.js               C:\util\hash.js

The sort function:

  • Works well with all kinds of paths on all platforms on which Node.js can be installed.
  • Parses and sorts paths based on the platform on which it is running. See the Platforms section below for details.
  • Normalizes path strings, but it always returns same strings/objects from the original array.
  • Does not access the file system, it just works with the strings.
  • By design, does not throw any exceptions related to the content of the paths array.

Installation and Usage

$ npm install cross-path-sort

This particular example will produce the same results on all platforms since the forward slash / is a valid separator on both Windows and POSIX (Linux, Unix, macOS...) systems:

const crossPathSort = require('cross-path-sort');
 
const paths = [
  'one.js',
  'test/one_spec.js', 
  '/mylibs/hash.js',
  'two.js',
  '/mylibs/encode/url.js',
  '/mylibs/assign.js',
  'test/shared/init.js',
  'test/two_spec.js',
  'config/env.js'
];
 
const sortedPaths1 = crossPathSort.sort(paths, { shallowFirst: true });
/*
  [
    'one.js',
    'two.js',
    'config/env.js',
    'test/one_spec.js',
    'test/two_spec.js',
    'test/shared/init.js',
    '/mylibs/assign.js',
    '/mylibs/hash.js',
    '/mylibs/encode/url.js'
  ]
*/
 
const sortedPaths2 = crossPathSort.sort(paths, { deepFirst: true });
/*
  [
    'config/env.js',
    'test/shared/init.js',
    'test/one_spec.js',
    'test/two_spec.js',
    'one.js',
    'two.js',
    '/mylibs/encode/url.js',
    '/mylibs/assign.js',
    '/mylibs/hash.js'
  ]
*/
 
// if you just want to separate path types
const sortedPaths3 = crossPathSort.sort(paths);
/*
  [
    'config/env.js',
    'one.js',
    'test/one_spec.js',
    'test/shared/init.js',
    'test/two_spec.js',
    'two.js',
    '/mylibs/assign.js',
    '/mylibs/encode/url.js',
    '/mylibs/hash.js'
  ]
*/

Had we used the backslash \ instead, results would be different on different platforms.

Platforms

The cross-platform sorting function assumes that the paths it works on are related to the operating system on which it is running. In other words, it assumes that the paths are either locally generated by your application or specified by its user.

The paths are normalized, parsed and sorted accordingly.

This module exposes three functions:

  • sort() is the cross-platform sorting function, which you should use.
  • posix.sort() is POSIX-specific sorting function.
  • windows.sort() is Windows-specific sorting function.

Depending on the local platform, sort() works like posix.sort() or windows.sort().

You should always use just sort() unless you have a specific application that doesn't work with local paths.

const crossPathSort = require('cross-path-sort');
 
// escaped backslash
const paths = ['b\\a.js', 'c.js', 'a.js'];
 
// on windows: b\a.js = file a.js in subdirectory b
const sortedOnWindows = crossPathSort.windows.sort(paths, { shallowFirst: true });
/*
  [
    'a.js', 
    'c.js', 
    'b\\a.js'
  ]
*/
 
// on posix: b\a.js = file b\a.js
const sortedOnPosix = crossPathSort.posix.sort(paths, { shallowFirst: true });
/*
  [
    'a.js', 
    'b\\a.js',
    'c.js' 
  ]
*/
 
const sortedLocally = crossPathSort.sort(paths, { shallowFirst: true });
/*
  same as sortedOnWindows or sortedOnPosix, depending on your platform
*/

All three functions have the same signature.

sort(paths, options)

parameters

paths is an array of path strings or objects, see the paths and pathKey sections.

options is an options object. All options are optional, and the whole object is optional.

returns

The function returns a new, sorted array with the exact same elements from the paths array.

exceptions

Only if you specify invalid options. See the options below for details.

example

All options with their default values:

const sortedPaths = crossPathSort.sort(paths, {
  pathKey: undefined,
  shallowFirst: false,
  deepFirst: false,
  homePathsSupported: false,
  posixOrder: ['rel', 'home', 'abs'],
  windowsOrder: ['rel', 'home', 'abs', 'drel', 'dabs', 'unc', 'nms'],
  segmentCompareFn: (a, b) => a.localeCompare(b)
});

paths

Array of strings or objects, or even a mixed array of strings and objects.

By design, this array can contain anything:

  • string elements and object elements whose object[pathKey] is string will be treated equally and sorted.
  • All other elements will be treated as 'unreadable' and come after the sorted elements.
  • Holes will be preserved and come at the very end of the resulting array.

If paths is not an array, sort() will simply return the same value.

pathKey

If you want to sort an array of your custom objects that contain path strings, use the pathKey option to specify the key of a property whose value represents the path string.

If specified, pathKey should be a string.

Path string of an object element from the paths array will be read from object[pathKey].

Notes:

  • If your array has a mixed content, pathKey will be used only for object elements and ignored for string elements (string element itself represents a path).
  • If object[pathKey] is not a string, that object element will be treated as 'unreadable'.
  • If you don't specify pathKey, all object elements will be treated as 'unreadable'.

Example:

const crossPathSort = require('cross-path-sort');
 
const obj1 = { file: 'c.js' };
const obj2 = { file: 'b/a.js' };
const obj3 = {};
const obj4 = { file: 'a.js'};
const paths = [obj1, obj2, obj3, obj4];
 
const sortedPaths = crossPathSort.sort(paths, { 
  pathKey: 'file',
  shallowFirst: true 
});
/*
  [obj4, obj1, obj2, obj3]
*/

If your array contains just string elements, you can leave this value undefined.

sort() will throw an exception if the pathKey argument itself is not a string or undefined.

sort() will NOT throw an exception if object[pathKey] is not a string.

shallowFirst & deepFirst

Default values are false. Only one can be set to true.

Sort has three modes:

  • If shallowFirst is true, content of a directory will come before the content of its subdirectories.
  • If deepFirst is true, content of a directory will come after the content of its subdirectories.
  • If both values are false, file names will be compared with subdirectory names.

See the example in the Installation and Usage section above.

sort() will throw an exception if both shallowFirst and deepFirst have a truthy value.

homePathsSupported

Default value is false and paths starting with ~ are treated as relative paths, as the tilde is a valid character for file names and directory names on all systems.

This is in line with how Node's modules such as fs or path treat these paths.

If your application explicitly supports shell-specific paths like ~/ or ~user/, and you want the paths starting with ~ to appear in a different partition of the resulting array as home paths, set this value to true.

Regarding the next section:

  • If homePathsSupported is false, paths starting with ~ will be 'rel' paths. There will be no home paths.
  • If homePathsSupported is true, paths starting with ~ will be 'home' paths.

posixOrder & windowsOrder

These options specify the order of different path types in the resulting array.

sort() uses posixOrder on POSIX platforms, windowsOrder on Windows platforms.

POSIX path types

  • 'rel' are relative paths, such as a.js and b/a.js.
  • 'home' are home paths, see the previous section.
  • 'abs' are absolute paths, such as /a.js and /b/a.js.

posixOrder default value is: ['rel', 'home', 'abs']

Windows path types

  • 'rel' are relative paths, such as a.js and b\a.js
  • 'home' are home paths, see the previous section.
  • 'abs' are absolute paths, such as \a.js and \b\a.js.
  • 'drel' are relative paths with a specified drive, such as C:a.js and C:b\a.js.
  • 'dabs' are absolute paths with a specified drive, such as C:\a.js and C:\b\a.js.
  • 'unc' are UNC paths, such as \\server\share\a.js and \\server\share\b\a.js.
  • 'nms' are namespaced paths - paths starting with \\?\ or \\.\.

windowsOrder default value is: ['rel', 'home', 'abs', 'drel', 'dabs', 'unc', 'nms']

Since the forward slash / is a valid separator on Windows, paths like /a.js on Windows are also 'abs' type paths, paths like C:/a.js on Windows are also 'dabs' type paths etc.

Example:

const crossPathSort = require('cross-path-sort');
 
const paths = [
  'one.js',
  'test/one_spec.js', 
  '/mylibs/hash.js',
  'two.js',
  '/mylibs/encode/url.js',
  '/mylibs/assign.js',
  'test/shared/init.js',
  'test/two_spec.js',
  'config/env.js'
];
 
// position of the 'home' type is irrelevant if homePathsSupported is not true
const sortedPaths1 = crossPathSort.sort(paths, { 
  shallowFirst: true,
  posixOrder: ['abs', 'home', 'rel'],
  windowsOrder: ['abs', 'dabs', 'unc', 'nms', 'drel', 'home', 'rel']
});
/*
  [
    '/mylibs/assign.js',
    '/mylibs/hash.js',
    '/mylibs/encode/url.js',
    'one.js',
    'two.js',
    'config/env.js',
    'test/one_spec.js',
    'test/two_spec.js',
    'test/shared/init.js'
  ]
*/

sort() will throw an exception if the posixOrder argument is not an array or undefined. An array must be a permutation of the default array. The same applies to the windowsOrder argument.

segmentCompareFn

Function used to compare path segments such as file names, directory names, drive letters etc.

Default function is: (a, b) => a.localeCompare(b)

If you don't specify this option, the default function will be used.

Your custom function should work like a function you would use with Array.prototype.sort().

The function will always get two string values, and should return a number that is < 0, 0 or > 0.

sort() will throw an exception if segmentCompareFn is not a function or undefined. Also, sort() does not catch exceptions thrown by your function. If your function throws an exception, the whole sort() will throw that exception.

About

Author

Milos Djermanovic

License

MIT License

Package Sidebar

Install

npm i cross-path-sort

Weekly Downloads

1,250

Version

1.0.0

License

MIT

Unpacked Size

26.4 kB

Total Files

4

Last publish

Collaborators

  • mdjermanovic