├── .clang-format ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── package.json ├── pedant.js └── test └── test.js /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: JavaScript 3 | # BasedOnStyle: Google 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlinesLeft: true 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: true 16 | AllowShortLoopsOnASingleLine: true 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: false 25 | AfterControlStatement: false 26 | AfterEnum: false 27 | AfterFunction: false 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: false 31 | AfterUnion: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | BreakBeforeBinaryOperators: None 36 | BreakBeforeBraces: Attach 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: false 39 | ColumnLimit: 80 40 | CommentPragmas: '^ IWYU pragma:' 41 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 42 | ConstructorInitializerIndentWidth: 4 43 | ContinuationIndentWidth: 4 44 | Cpp11BracedListStyle: true 45 | DerivePointerAlignment: true 46 | DisableFormat: false 47 | ExperimentalAutoDetectBinPacking: false 48 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 49 | IncludeCategories: 50 | - Regex: '^<.*\.h>' 51 | Priority: 1 52 | - Regex: '^<.*' 53 | Priority: 2 54 | - Regex: '.*' 55 | Priority: 3 56 | IndentCaseLabels: true 57 | IndentWidth: 2 58 | IndentWrappedFunctionNames: false 59 | KeepEmptyLinesAtTheStartOfBlocks: false 60 | MacroBlockBegin: '' 61 | MacroBlockEnd: '' 62 | MaxEmptyLinesToKeep: 1 63 | NamespaceIndentation: None 64 | ObjCBlockIndentWidth: 2 65 | ObjCSpaceAfterProperty: false 66 | ObjCSpaceBeforeProtocolList: false 67 | PenaltyBreakBeforeFirstCallParameter: 1 68 | PenaltyBreakComment: 300 69 | PenaltyBreakFirstLessLess: 120 70 | PenaltyBreakString: 1000 71 | PenaltyExcessCharacter: 1000000 72 | PenaltyReturnTypeOnItsOwnLine: 200 73 | PointerAlignment: Left 74 | ReflowComments: true 75 | SortIncludes: true 76 | SpaceAfterCStyleCast: false 77 | SpaceBeforeAssignmentOperators: true 78 | SpaceBeforeParens: ControlStatements 79 | SpaceInEmptyParentheses: false 80 | SpacesBeforeTrailingComments: 2 81 | SpacesInAngles: false 82 | SpacesInContainerLiterals: true 83 | SpacesInCStyleCastParentheses: false 84 | SpacesInParentheses: false 85 | SpacesInSquareBrackets: false 86 | Standard: Auto 87 | TabWidth: 8 88 | UseTab: Never 89 | ... 90 | 91 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # Swap files from vim 40 | *.swp 41 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for contributing to Pedant! Just remember before you contribute, we ask that you follow Google's style guide for JavaScript. 4 | 5 | It's actually pretty easy: just before you run `git commit` just run `clang-format -i pedant.js` first, to make the code-style consistent. 6 | 7 | If you're running Ubuntu/Debian, you can install clang-format by `apt-get install clang-format`. 8 | 9 | If you're on a mac and have Homebrew installed, you can run `brew install clang-format` to get it. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Decagon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm version](https://badge.fury.io/js/pedantjs.svg)](https://badge.fury.io/js/pedantjs) [![travis cli](https://travis-ci.org/Decagon/pedant.svg)](https://travis-ci.org/Decagon/pedant/branches) [![downloads](https://img.shields.io/npm/dm/pedantjs.svg)](https://www.npmjs.com/package/pedantjs) [![Join the chat at https://gitter.im/Decagon/pedant](https://badges.gitter.im/Decagon/pedant.svg)](https://gitter.im/Decagon/pedant?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Codewake](https://www.codewake.com/badges/codewake.svg)](https://www.codewake.com/p/pedant-6ffb4c6e-0a50-4587-9882-5e798664c6f3) 2 | 3 | # Pedant 4 | 5 | **Pedant** finds and fixes punctuation and formatting errors in English texts, that grammar checkers miss. 6 | 7 | ```javascript 8 | pedant.validate('The quick brown fox,jumped over the lazy dog') 9 | // punctuation error at index 16 (missing space after comma): 10 | // ...ck brown,fox jumped over... 11 | ``` 12 | 13 | Pedant finds small errors that spell checkers, grammar checkers, and style correctors usually miss. For example, if I start a quote "like this, then forget to end it--writing my readme in the meantime--pedant will let me know. 14 | 15 | Sometimes, you might hit the spacebar twice, making an ugly ` ` double space. Or, when you hit. a period in the middle of a sentence, or a strange amount of periods the end.. or mix punctuation,. Pedant will let you know about that too. 16 | 17 | Or, when you forget to add a space after a punctuation mark,like this. Overall, these mistakes can add up, and make your writing look unprofessional. 18 | 19 | ## Roadmap 20 | 21 | Here are some of the features that we are developing to add to Pedant (subject to change.) **Note:** any of these features can be turned on or off, depending on your style of writing: 22 | ### Parenthesis 23 | - unnecessarily nested parenthesis ((like this for example)) 24 | - parenthesis nested too deep (this sentence (yes, this one (the one that you are reading, right now) right here) is too complex because there are too many parentheses (those bracket shaped things))))). We're not writing lisp code. 25 | - parenthesis nested, but nested parenthesis are not square brackets 26 | - placing periods outside of parentheses ). and .) 27 | 28 | ### Punctuation and Spacing 29 | - extra (or not enough) spaces after punctuation 30 | - too many punctuation symbols!!! 31 | - placing punctuation inside/outside of quote 32 | - usage of -- instead of an em-dash or another suitable alternative 33 | - warnings when using the Greek semicolon and regular semicolon together 34 | - warnings when using unprintable zero-width characters 35 | - warnings when trying to center text by repeatedly using the spacebar (and option to automatically center) 36 | - warnings when adding more than two line breaks after a paragraph 37 | 38 | #### Inconsistencies 39 | - inconsistencies when using the oxford comma 40 | - inconsistencies when a word is hyphenated and isn't (e.g. merry-go-round and merry go round) and variants 41 | - when a word is Suddenly capitalized in one sentence not after a period, then suddenly it isn't 42 | - extra spaces in front of lists 43 | - extra spaces at the end of sentences, even if the next character isn't punctuation 44 | - inconsistencies when adding a period at the end of a list item, and keeping the others without one. 45 | 46 | ### Quotes 47 | - usage of different spellings of the same word (e.g. color and colour), with option to allow quoted material to bypass 48 | - long quotes with missing author 49 | - warnings when adding or subtracting words from a quote after it has been written, without using the proper [inserted-word-here] notation* 50 | 51 | ### Lists 52 | - empty list items (or an extra empty list item) 53 | - inconsistent capitalizatioN 54 | - warnings for starting the list with the same word many times 55 | - warnings when using the same list item multiple times in a row 56 | - warnings when using the same list item multiple times in a row, with small changes 57 | 58 | ### Fonts 59 | - warnings when bolding, italizing, or underlining an entire word, except the last or first **lette**r, or when it extends past the word into the space after it, **like this w**hich can be annoying 60 | 61 | ### Mixed Languages and Cultures 62 | - support for other languages (e.g. French requires that a space is placed before punctuation like this !) 63 | - errors when using English quotes around a pure French or other language quote 64 | - warnings when specifying the type of currency, but using an incorrect symbol (it cost $10 pounds) and suggestions to use the currency symbol instead of the word, if both are used 65 | 66 | ### People and Books 67 | - warnings when addressing someone by Ms., Mrs., or Miz., and then using the opposite gender pronoun in the next sentence, (excluding non-gender pronouns like "they" or "them") without mentioning any other names and vice-versa 68 | - warnings when addressing people by their first name if two or more people exist with the same first name but have different last names 69 | - warnings in novel mode when typing a character's name, but differs by one letter from another character's and is only mentioned once 70 | 71 | ### Mathematical Notation and Precision 72 | - suggestions for spelling out natural numbers smaller than 10, and when starting a sentence with a number 73 | - warnings when mathematical notation contains (possibly) ambiguous order of operations (e.g. 4*5+2-9/2) 74 | - warnings when mixing precisions with currency values (e.g. it cost $10 and the other thing cost $20.00), since both could be expressed with no cent values, since they are both zero 75 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pedantjs", 3 | "version": "1.0.1", 4 | "description": "Find and fix bothersome punctuation and formatting errors in English texts.", 5 | "main": "pedant.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "chai": "^3.5.0" 12 | }, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 0" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/Decagon/Pedant.git" 19 | }, 20 | "author": "Decagon", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/Decagon/Pedant/issues" 24 | }, 25 | "homepage": "https://github.com/Decagon/Pedant#readme" 26 | } 27 | -------------------------------------------------------------------------------- /pedant.js: -------------------------------------------------------------------------------- 1 | var pedant = { 2 | validate : function(lines) { 3 | var inQuote = false; 4 | var currQuoteLength = 0; 5 | var quoteStartIndex = 0; 6 | var MAX_QUOTE_LENGTH = 20; 7 | var MAX_PUNCTUATION_LENGTH = 3; 8 | var punctuation = [ ',', '.', '!', ';', ';', '"' ]; 9 | var punctuationAmount = 0; 10 | var punctuationStartIndex = 0; 11 | var quotes = [ '"', "'" ]; 12 | var contractionEndings = 13 | [ 't', 's', 'm', 're', 's', 've', 'd', 'll', 'em' ]; 14 | 15 | function printError(msg, type, line, col) { 16 | console.log(msg + ", " + type + ", line " + (line + 1) + ", col " + 17 | (col + 1)); 18 | } 19 | 20 | lines = lines.split("\n"); 21 | for (var j = 0; j < lines.length; j++) { 22 | text = lines[j]; 23 | for (var i = 0; i < text.length; i++) { 24 | if ("(".indexOf(text[i]) > -1) { 25 | if ("(".indexOf(text[i + 1]) > -1) { 26 | printError("too many parenthesis", "PunctuationError", j, i); 27 | } 28 | } 29 | 30 | if (punctuation.indexOf(text[i]) > -1) { 31 | if (punctuationAmount == 0) { 32 | punctuationStartIndex = i; 33 | } 34 | punctuationAmount++; 35 | 36 | if ((text[i + 1] != ")") && (text[i + 1] != " ")) { 37 | printError("no space after punctuation", "PunctuationError", j, 38 | punctuationStartIndex); 39 | } 40 | 41 | } else { 42 | punctuationStartIndex = 0; 43 | punctuationAmount = 0; 44 | } 45 | if (punctuationAmount > MAX_PUNCTUATION_LENGTH) { 46 | printError("too much punctuation", "PunctuationError", j, 47 | punctuationStartIndex); 48 | 49 | punctuationStartIndex = 0; 50 | punctuationAmount = 0; 51 | } 52 | 53 | // on a space 54 | if (" ".indexOf(text[i]) > -1) { 55 | if (((text[i + 1] == " ") || (text[i + 1] == ")"))) { 56 | printError("too much whitespace", "WhitespaceError", j, i); 57 | } 58 | } 59 | // found a quote that didn't end after sentence 60 | if ((text[i + 1] == undefined) && inQuote) { 61 | inQuote = false; 62 | printError("unclosed quote", "QuoteError", j, quoteStartIndex); 63 | } 64 | 65 | // okay, we found a quote 66 | if (quotes.indexOf(text[i]) > -1) { 67 | // proper contraction detection using xor 68 | var a = ((contractionEndings.indexOf(text[i + 1]) == -1)); 69 | var b = text[i] == "'"; 70 | var xor = (a ? !b : b); 71 | if ((!inQuote) && !xor) { 72 | quoteStartIndex = i; 73 | inQuote = true; 74 | } else { 75 | if ((i - quoteStartIndex) > MAX_QUOTE_LENGTH) { 76 | printError("quote too long", "QuoteError", j, quoteStartIndex); 77 | inQuote = false; 78 | } 79 | } 80 | } 81 | } 82 | } 83 | } 84 | }; 85 | 86 | module.exports = pedant; 87 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('chai').assert; 2 | --------------------------------------------------------------------------------