Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement, document, and test 'amendOrphan' #14

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Implement, document, and test 'amendOrphan'
phil olson committed May 7, 2016
commit 790d5a2c5cc60e5fbf8b2df087fcc14d24854466
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -119,6 +119,30 @@ Break a word between any two letters when the word is longer than the specified
wrap(str, {cut: true});
```

### options.amendOrphan

Type: `Boolean`

Default: `false`

Amends the last line in the case it has one word. Only occurs when:
- there's more than one line,
- the second to last line has more than one word
- the amended line would not pass [width](#options.width)
- [options.cut](#options.cut) is not true.

**Example:**

```js
// 1
// 12345678901234567
var str = 'This is an orphan';
wrap(str, {width: 10, amendOrphan: true});
// returns
// This is
// an orphan
```

## Related projects

* [common-words](https://www.npmjs.com/package/common-words): Updated list (JSON) of the 100 most common words in the English language. Useful for… [more](https://www.npmjs.com/package/common-words) | [homepage](https://github.com/jonschlinkert/common-words)
@@ -152,4 +176,4 @@ Released under the MIT license.

***

_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on August 28, 2015._
_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on August 28, 2015._
62 changes: 60 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -21,8 +21,8 @@ module.exports = function(str, options) {

var newline = options.newline || '\n' + indent;

function identity(str) {
return str;
function identity(str) {
return str;
};
var escape = typeof options.escape === 'function'
? options.escape
@@ -35,10 +35,68 @@ module.exports = function(str, options) {
}

var lines = str.match(re) || [];

// Incompatible with cut because there's no easy way to determine whether
// the last line was cut mid-word
if (!options.cut && options.amendOrphan === true) {
lines = handleOrphan(lines, width);
}

var res = indent + lines.map(escape).join(newline);

if (options.trim === true) {
res = res.replace(/[ \t]*$/gm, '');
}
return res;
};

function handleOrphan(lines, width) {
var len = lines.length
// WS: word separator
, WS = /\s+/
, lastLine = lines[len - 1]
, secondToLastLine = lines[len - 2]
, orphanAdopter = getLastWord(secondToLastLine)
, amendedLastLine = orphanAdopter + ' ' + lastLine;

// we only want to handle orphans when:
// - there's more than one line,
// - the second to last line has more than one word
// - the last line has only a single word
// - the amended line would not pass width
var shouldHandleOrphan = len > 1
&& secondToLastLine.trim()
.split(WS)
.length > 1
&& lastLine.trim()
.split(WS)
.length === 1
&& width >= amendedLastLine.length;

if (shouldHandleOrphan) {
// remove the last two elements from the array
lines.splice(-2);

// we need to remove trailing whitespace from the secondToLastLine in order
// to remove the orphanAdopter correctly
secondToLastLine = removeTrailingSpace(secondToLastLine);

// remove orphanAdopter
secondToLastLine = secondToLastLine.slice(0, secondToLastLine.length - orphanAdopter.length);

lines = lines.concat(secondToLastLine, amendedLastLine);
}

return lines;

// helper functions
function getLastWord(line) {
var words = line.split(WS);
// if the last element in the array is an empty string (resulting from the
// regex split), then we call pop again to get the word.
return words.pop() || words.pop();
}
function removeTrailingSpace(str) {
return str.replace(/^(.*?)[\s]*$/, '$1');
}
}
13 changes: 12 additions & 1 deletion test.js
Original file line number Diff line number Diff line change
@@ -49,6 +49,17 @@ describe('wrap', function () {

it('should cut long words', function() {
assert.equal(wrap('Supercalifragilisticexpialidocious and Supercalifragilisticexpialidocious', {width:24, cut:true}), ' Supercalifragilisticexpi\n alidocious and Supercali\n fragilisticexpialidociou\n s');
})
});

it('should handle orphans', function() {
assert.equal(wrap('This is an orphan', {width:10, amendOrphan:true}), ' This is \n an orphan');

// handle more than a single whitespace character between orphan and orphan adopter to keep existing functionality
assert.equal(wrap('This is \t an orphan', {width:10, amendOrphan:true}), ' This is \t \n an orphan');

assert.equal(wrap('Nope, no orphan here', {width:11, amendOrphan:true}), ' Nope, no \n orphan here');

// don't handle if the amended line length would be greater than width
assert.equal(wrap("Don't amend orphan", {width:11, amendOrphan:true}), " Don't amend \n orphan");
});
});