├── .eslintrc.json ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── keymaps └── markdown-table-editor.json ├── lib ├── controller.js ├── editor-controller.js ├── markdown-table-editor.js └── text-editor-interface.js ├── menus └── markdown-table-editor.json ├── package-lock.json ├── package.json └── spec ├── .eslintrc.json ├── markdown-table-editor-spec.js └── text-editor-interface-spec.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 8, 4 | "sourceType": "module" 5 | }, 6 | "env": { 7 | "es6": true, 8 | "node": true, 9 | "browser": true 10 | }, 11 | "globals": { 12 | "atom": true 13 | }, 14 | "extends": "eslint:recommended", 15 | "rules": { 16 | "for-direction": ["warn"], 17 | "getter-return": ["error"], 18 | "no-cond-assign": ["warn", "always"], 19 | "no-control-regex": ["off"], 20 | "no-template-curly-in-string": ["warn"], 21 | "no-unsafe-negation": ["error"], 22 | "valid-jsdoc": ["warn", { 23 | "requireParamDescription": false, 24 | "requireReturnDescription": false }], 25 | 26 | "array-callback-return": ["error"], 27 | "consistent-return": ["error"], 28 | "curly": ["error"], 29 | "default-case": ["error"], 30 | "dot-location": ["error", "property"], 31 | "eqeqeq": ["error"], 32 | "no-alert": ["error"], 33 | "no-caller": ["error"], 34 | "no-eval": ["error"], 35 | "no-extend-native": ["error"], 36 | "no-extra-bind": ["error"], 37 | "no-extra-label": ["error"], 38 | "no-floating-decimal": ["error"], 39 | "no-implicit-coercion": ["error", { 40 | "allow": ["!!"] }], 41 | "no-implicit-globals": ["error"], 42 | "no-implied-eval": ["error"], 43 | "no-invalid-this": ["warn"], 44 | "no-iterator": ["error"], 45 | "no-lone-blocks": ["error"], 46 | "no-loop-func": ["error"], 47 | "no-multi-str": ["error"], 48 | "no-new": ["error"], 49 | "no-param-reassign": ["error"], 50 | "no-proto": ["error"], 51 | "no-return-assign": ["error"], 52 | "no-return-await": ["error"], 53 | "no-self-compare": ["error"], 54 | "no-sequences": ["error"], 55 | "no-throw-literal": ["warn"], 56 | "no-unmodified-loop-condition": ["error"], 57 | "no-unused-expressions": ["error"], 58 | "no-useless-call": ["error"], 59 | "no-useless-concat": ["error"], 60 | "no-useless-return": ["error"], 61 | "no-void": ["error"], 62 | "no-warning-comments": ["warn"], 63 | "no-with": ["error"], 64 | "require-await": ["warn"], 65 | "wrap-iife": ["error"], 66 | 67 | "strict": ["error"], 68 | 69 | "no-label-var": ["error"], 70 | "no-shadow-restricted-names": ["error"], 71 | "no-unused-vars": ["error", { 72 | "args": "none" }], 73 | "no-use-before-define": ["error", { 74 | "functions": false, 75 | "classes": false }], 76 | 77 | "array-bracket-spacing": ["error", "never"], 78 | "block-spacing": ["error", "always"], 79 | "brace-style": ["error", "stroustrup", { 80 | "allowSingleLine": true }], 81 | "camelcase": ["error", { 82 | "properties": "never" }], 83 | "comma-dangle": ["error", "only-multiline"], 84 | "comma-spacing": ["error", { 85 | "before": false, 86 | "after": true }], 87 | "comma-style": ["error", "last"], 88 | "computed-property-spacing": ["error", "never"], 89 | "eol-last": ["error"], 90 | "func-call-spacing": ["error", "never"], 91 | "func-name-matching": ["error"], 92 | "func-style": ["error", "declaration", { 93 | "allowArrowFunctions": true }], 94 | "indent": ["error", 2, { 95 | "VariableDeclarator": { 96 | "var": 2, 97 | "let": 2, 98 | "const": 3 }, 99 | "ignoredNodes": ["ConditionalExpression"] }], 100 | "jsx-quotes": ["error", "prefer-double"], 101 | "key-spacing": ["error", { 102 | "beforeColon": false, 103 | "afterColon": true, 104 | "align": "colon" }], 105 | "keyword-spacing": ["error", { 106 | "before": true, 107 | "after": true }], 108 | "linebreak-style": ["error", "unix"], 109 | "lines-between-class-members": ["error", "always", { 110 | "exceptAfterSingleLine": true }], 111 | "max-len": ["error", { 112 | "code": 100, 113 | "ignoreComments": true, 114 | "ignoreStrings": true, 115 | "ignoreTemplateLiterals": true, 116 | "ignoreRegExpLiterals": true }], 117 | "new-cap": ["error"], 118 | "new-parens": ["error"], 119 | "no-array-constructor": ["error"], 120 | "no-multi-assign": ["error"], 121 | "no-multiple-empty-lines": ["error", { 122 | "max": 2, 123 | "maxBOF": 0, 124 | "maxEOF": 0 }], 125 | "no-new-object": ["error"], 126 | "no-plusplus": ["error", { 127 | "allowForLoopAfterthoughts": true }], 128 | "no-tabs": ["error"], 129 | "no-trailing-spaces": ["error"], 130 | "no-unneeded-ternary": ["error"], 131 | "no-whitespace-before-property": ["error"], 132 | "object-curly-spacing": ["error", "always"], 133 | "operator-linebreak": ["error", "before", { 134 | "overrides": { 135 | "=": "after", 136 | "+=": "after", 137 | "-=": "after", 138 | "*=": "after", 139 | "/=": "after", 140 | "%=": "after", 141 | "**=": "after", 142 | "<<=": "after", 143 | ">>=": "after", 144 | ">>>=": "after", 145 | "&=": "after", 146 | "^=": "after", 147 | "|=": "after" } }], 148 | "padded-blocks": ["error", "never"], 149 | "quote-props": ["error", "consistent-as-needed"], 150 | "quotes": ["error", "double"], 151 | "semi": ["error", "always"], 152 | "semi-spacing": ["error", { 153 | "before": false, 154 | "after": true }], 155 | "semi-style": ["error", "last"], 156 | "space-before-blocks": ["error", "always"], 157 | "space-before-function-paren": ["error", { 158 | "anonymous": "always", 159 | "named": "never" }], 160 | "space-in-parens": ["error", "never"], 161 | "space-infix-ops": ["error"], 162 | "space-unary-ops": ["error", { 163 | "words": true, 164 | "nonwords": false }], 165 | "spaced-comment": ["error", "always"], 166 | "switch-colon-spacing": ["error", { 167 | "before": false, 168 | "after": true }], 169 | "template-tag-spacing": ["error", "never"], 170 | "unicode-bom": ["error", "never"], 171 | 172 | "arrow-body-style": ["error", "as-needed"], 173 | "arrow-parens": ["error", "as-needed"], 174 | "arrow-spacing": ["error", { 175 | "before": true, 176 | "after": true }], 177 | "generator-star-spacing": ["error", { 178 | "before": false, 179 | "after": true, 180 | "method": { 181 | "before": true, 182 | "after": false } }], 183 | "no-duplicate-imports": ["error"], 184 | "no-useless-computed-key": ["error"], 185 | "no-var": ["error"], 186 | "prefer-arrow-callback": ["error"], 187 | "prefer-const": ["error"], 188 | "prefer-numeric-literals": ["error"], 189 | "prefer-rest-params": ["error"], 190 | "prefer-spread": ["error"], 191 | "require-yield": ["warn"], 192 | "rest-spread-spacing": ["error", "never"], 193 | "yield-star-spacing": ["error", { 194 | "before": false, 195 | "after": true }] 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/e9c3096114fd81b92cf989f7343d7b168b80d994/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # next.js build output 63 | .next 64 | 65 | # Temporary/working files 66 | temp/ 67 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1.3 2 | * Fix [#31](https://github.com/susisu/atom-markdown-table-editor/issues/31) 3 | * Update Unicode East Asian Width to 13.0.0 4 | 5 | ## 1.1.2 6 | * Update dependencies 7 | * In particular, update Unicode East Asian Width to 12.1.0 8 | 9 | ## 1.1.1 10 | * Add "Set Format Type" commands that can explicitly change "Format Type" config 11 | * Show notifications when config is changed by the commands 12 | 13 | ## 1.1.0 14 | * Add "Left Margin Characters" config 15 | - For example, you can enable markdown-table-editor in JavaScript comments by adding `comment.block.documentation.js` to "Scopes" and `*` to "Left Margin Characters". 16 | 17 | ## 1.0.2 18 | * Disable Esc keymap in [vim-mode-plus](https://atom.io/packages/vim-mode-plus) 19 | 20 | ## 1.0.1 21 | * Fix a problem about smart cursor 22 | 23 | ## 1.0.0 24 | * Overhauled using [mte-kernel](https://github.com/susisu/mte-kernel) 25 | * Add "Format All" command 26 | * Add "Format On Save" option and "Toggle Format On Save" command 27 | * Add "Unicode Normalization" option for computing text widths 28 | * Enable "Smart Cursor" by default 29 | * Rename some options (old ones will be automatically migrated to the new ones) 30 | 31 | ## 0.6.4 32 | * Add "Move Row" and "Move Column" commands 33 | 34 | ## 0.6.3 35 | * Add config to change default cell alignment and header cell alignment 36 | 37 | ## 0.6.2 38 | * Add menu items 39 | * Add "Format Type" config, which specifies how a table is formatted on each operation 40 | * Add a command to switch the format type 41 | 42 | ## 0.6.1 43 | * Fix error when trying to align a column but the cursor is out of the table ([#4](https://github.com/susisu/markdown-table-editor/issues/4)) 44 | 45 | ## 0.6.0 46 | * Use scopes instead of grammar to determine active or not 47 | - The default config is changed from `source.gfm, text.md` to `table.gfm, table.storage.md` 48 | 49 | ## 0.5.2 50 | * Small improvements 51 | 52 | ## 0.5.1 53 | * Replace library for computing East Asian Width property 54 | 55 | ## 0.5.0 56 | * Always enable Unicode East Asian Width features 57 | * Disable "Treat East Asian Ambiguous Characters As Wide" by default 58 | 59 | ## 0.4.4 60 | * Add "Always Wide/Narrow Characters" settings, allows to override character width 61 | 62 | ## 0.4.3 63 | * Small change 64 | 65 | ## 0.4.2 66 | * Add "Treat East Asian Ambiguous Characters As Wide" option 67 | 68 | ## 0.4.1 69 | * Improve settings' descriptions 70 | 71 | ## 0.4.0 72 | * Modify behavior of "Next Cell" 73 | - To move to the next row from the right end, press `enter` instead of `tab` 74 | 75 | ## 0.3.0 76 | * Add "Smart Cursor" option, which enables more sophisticated cursor movement (like MS Office) 77 | * Small changes 78 | 79 | ## 0.2.0 80 | * Add more commands 81 | * Small improvements 82 | 83 | ## 0.1.1 84 | * Adds description in `package.json` 85 | 86 | ## 0.1.0 87 | * First release 88 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Susisu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # markdown-table-editor 2 | Markdown table editor/formatter 3 | 4 | ![demo](https://github.com/susisu/markdown-table-editor/wiki/images/demo.gif) 5 | 6 | ## Quick guide 7 | 0. Set editor's grammar to `GitHub Markdown` or `Markdown`. 8 | 1. Input a pipe `|` and some content (the cursor position is indicated by `_`). 9 | ``` markdown 10 | | foo_ 11 | ``` 12 | (If you are using [language-markdown](https://atom.io/packages/language-markdown), don't forget a space after a pipe.) 13 | 2. Hit tab to move to the next cell. 14 | ``` markdown 15 | | foo | _ 16 | | --- | 17 | ``` 18 | 3. Continue typing. 19 | ``` markdown 20 | | foo | bar | _ 21 | | --- | --- | 22 | ``` 23 | 4. Hit enter to move to the next row. 24 | ``` markdown 25 | | foo | bar | 26 | | --- | --- | 27 | | _ | | 28 | ``` 29 | 5. Continue typing... 30 | ``` markdown 31 | | foo | bar | 32 | | --- | --- | 33 | | baz | _ | 34 | ``` 35 | 6. Hit esc to finish editing the table. 36 | ``` markdown 37 | | foo | bar | 38 | | --- | --- | 39 | | baz | | 40 | _ 41 | ``` 42 | 43 | ## Features 44 | * Format tables 45 | * Move the cursor from cell to cell 46 | * Alter column's alignment 47 | * Insert and delete rows and columns 48 | 49 | ### Commands 50 | | Name | Description | Keybinding | 51 | | ---------------------- | ---------------------------------------- | --------------------------------- | 52 | | Next Cell | Move to the next cell | tab | 53 | | Previous Cell | Move to the previous cell | shift + tab | 54 | | Next Row | Move to the next row | enter | 55 | | Escape | Escape from the table | escape | 56 | | Format | Just format the table | | 57 | | Format All | Format all the tables in the text editor | | 58 | | Align Left | Left-align the column | | 59 | | Align Right | Right-align the column | | 60 | | Align Center | Center-align the column | | 61 | | Align None | Unset alignment of the column | | 62 | | Select Cell | Select the cell content | | 63 | | Move Left | Move to the left cell | | 64 | | Move Right | Move to the right cell | | 65 | | Move Up | Move to the upper cell | | 66 | | Move Down | Move to the lower cell | | 67 | | Insert Row | Insert an empty row | | 68 | | Delete Row | Delete the row | | 69 | | Move Row Up | Move the row up | | 70 | | Move Row Down | Move the row down | | 71 | | Insert Column | Insert an empty column | | 72 | | Delete Column | Delete the column | | 73 | | Move Column Left | Move the column left | | 74 | | Move Column Right | Move the column right | | 75 | | Toggle Format On Save | Toggle "Format On Save" config | | 76 | | Switch Format Type | Switch "Format Type" config | | 77 | | Set Format Type Normal | Set "Format Type" config to "Normal" | | 78 | | Set Format Type Weak | Set "Format Type" config to "Weak" | | 79 | 80 | (To input a newline in a table, press shift + enter (or some equivalent) instead.) 81 | 82 | You can execute commands from the command palette (Windows, Linux: ctrl + shift + p / macOS: cmd + shift + p) or from the Packages menu. 83 | 84 | It will be more convenient if you add some keybindings to your `keymap.cson`. 85 | Here are the ones which I use: 86 | 87 | ``` coffee 88 | 'atom-text-editor:not(.mini):not(.autocomplete-active).markdown-table-editor-active': 89 | 'cmd-left' : 'markdown-table-editor:move-left' 90 | 'cmd-right' : 'markdown-table-editor:move-right' 91 | 'cmd-up' : 'markdown-table-editor:move-up' 92 | 'cmd-down' : 'markdown-table-editor:move-down' 93 | 'shift-cmd-left' : 'markdown-table-editor:align-left' 94 | 'shift-cmd-right' : 'markdown-table-editor:align-right' 95 | 'shift-cmd-up' : 'markdown-table-editor:align-center' 96 | 'shift-cmd-down' : 'markdown-table-editor:align-none' 97 | 'alt-shift-cmd-left' : 'markdown-table-editor:move-column-left' 98 | 'alt-shift-cmd-right': 'markdown-table-editor:move-column-right' 99 | 'alt-shift-cmd-up' : 'markdown-table-editor:move-row-up' 100 | 'alt-shift-cmd-down' : 'markdown-table-editor:move-row-down' 101 | 'cmd-k cmd-i' : 'markdown-table-editor:insert-row' 102 | 'cmd-k alt-cmd-i' : 'markdown-table-editor:delete-row' 103 | 'cmd-k cmd-j' : 'markdown-table-editor:insert-column' 104 | 'cmd-k alt-cmd-j' : 'markdown-table-editor:delete-column' 105 | ``` 106 | 107 | ## FAQ 108 | ### Q. My table does not align well when dealing with Chinese characters 109 | A. Use a monospaced font that includes glyphs for Chinese characters, such as [Noto Sans Mono CJK](https://github.com/googlei18n/noto-cjk). 110 | markdown-table-editor supports East Asian characters including Chinese characters :) 111 | 112 | ## For developers 113 | This package is based on [markdown-table-editor kernel](https://github.com/susisu/mte-kernel), which provides a text editor independent implementation of the functionality of the package. 114 | You can create a markdown-table-editor plugin for your favorite text editor with ease! 115 | -------------------------------------------------------------------------------- /keymaps/markdown-table-editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "atom-text-editor:not(.mini):not(.autocomplete-active).markdown-table-editor-active": { 3 | "tab" : "markdown-table-editor:next-cell", 4 | "shift-tab": "markdown-table-editor:previous-cell", 5 | "enter" : "markdown-table-editor:next-row" 6 | }, 7 | "atom-text-editor:not(.mini):not(.autocomplete-active):not(.vim-mode-plus).markdown-table-editor-active": { 8 | "escape": "markdown-table-editor:escape" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/controller.js: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable } from "atom"; 2 | import { FormatType } from "@susisu/mte-kernel"; 3 | 4 | import EditorController from "./editor-controller.js"; 5 | 6 | const COMMAND_TARGET = "atom-text-editor:not(.mini):not(.autocomplete-active)"; 7 | const EDITOR_COMMAND_TARGET = COMMAND_TARGET + ".markdown-table-editor-active"; 8 | const NAMESPACE = "markdown-table-editor"; 9 | 10 | const FORMAT_TYPES = [FormatType.NORMAL, FormatType.WEAK]; 11 | const FORMAT_TYPE_NAMES = { 12 | [FormatType.NORMAL]: "Normal", 13 | [FormatType.WEAK] : "Weak" 14 | }; 15 | 16 | export default class Controller { 17 | constructor() { 18 | this.editorCtrlers = new Map(); 19 | 20 | // event subscriptions 21 | this.subscriptions = new CompositeDisposable(); 22 | 23 | // editor 24 | this.subscriptions.add(atom.workspace.observeTextEditors(editor => { 25 | this.addEditor(editor); 26 | })); 27 | this.subscriptions.add(atom.workspace.onDidDestroyPaneItem(item => { 28 | this.removeEditor(item); 29 | })); 30 | 31 | // commands 32 | this.subscriptions.add(atom.commands.add(COMMAND_TARGET, { 33 | [`${NAMESPACE}:toggle-format-on-save`]: () => { 34 | this.toggleFormatOnSave(); 35 | }, 36 | [`${NAMESPACE}:switch-format-type`]: () => { 37 | this.switchFormatType(); 38 | }, 39 | [`${NAMESPACE}:set-format-type-normal`]: () => { 40 | this.setFormatType(FormatType.NORMAL); 41 | }, 42 | [`${NAMESPACE}:set-format-type-weak`]: () => { 43 | this.setFormatType(FormatType.WEAK); 44 | }, 45 | [`${NAMESPACE}:format-all`]: this.editorCommand(editorCtrler => { 46 | editorCtrler.formatAll(); 47 | }) 48 | })); 49 | this.subscriptions.add(atom.commands.add(EDITOR_COMMAND_TARGET, { 50 | [`${NAMESPACE}:format`]: this.editorCommand(editorCtrler => { 51 | editorCtrler.format(); 52 | }), 53 | [`${NAMESPACE}:escape`]: this.editorCommand(editorCtrler => { 54 | editorCtrler.escape(); 55 | }), 56 | [`${NAMESPACE}:align-left`]: this.editorCommand(editorCtrler => { 57 | editorCtrler.alignLeft(); 58 | }), 59 | [`${NAMESPACE}:align-right`]: this.editorCommand(editorCtrler => { 60 | editorCtrler.alignRight(); 61 | }), 62 | [`${NAMESPACE}:align-center`]: this.editorCommand(editorCtrler => { 63 | editorCtrler.alignCenter(); 64 | }), 65 | [`${NAMESPACE}:align-none`]: this.editorCommand(editorCtrler => { 66 | editorCtrler.alignNone(); 67 | }), 68 | [`${NAMESPACE}:align-default`]: this.editorCommand(editorCtrler => { 69 | editorCtrler.alignNone(); 70 | }), 71 | [`${NAMESPACE}:select-cell`]: this.editorCommand(editorCtrler => { 72 | editorCtrler.selectCell(); 73 | }), 74 | [`${NAMESPACE}:move-left`]: this.editorCommand(editorCtrler => { 75 | editorCtrler.moveLeft(); 76 | }), 77 | [`${NAMESPACE}:move-right`]: this.editorCommand(editorCtrler => { 78 | editorCtrler.moveRight(); 79 | }), 80 | [`${NAMESPACE}:move-up`]: this.editorCommand(editorCtrler => { 81 | editorCtrler.moveUp(); 82 | }), 83 | [`${NAMESPACE}:move-down`]: this.editorCommand(editorCtrler => { 84 | editorCtrler.moveDown(); 85 | }), 86 | [`${NAMESPACE}:next-cell`]: this.editorCommand(editorCtrler => { 87 | editorCtrler.nextCell(); 88 | }), 89 | [`${NAMESPACE}:previous-cell`]: this.editorCommand(editorCtrler => { 90 | editorCtrler.previousCell(); 91 | }), 92 | [`${NAMESPACE}:next-row`]: this.editorCommand(editorCtrler => { 93 | editorCtrler.nextRow(); 94 | }), 95 | [`${NAMESPACE}:insert-row`]: this.editorCommand(editorCtrler => { 96 | editorCtrler.insertRow(); 97 | }), 98 | [`${NAMESPACE}:delete-row`]: this.editorCommand(editorCtrler => { 99 | editorCtrler.deleteRow(); 100 | }), 101 | [`${NAMESPACE}:move-row-up`]: this.editorCommand(editorCtrler => { 102 | editorCtrler.moveRowUp(); 103 | }), 104 | [`${NAMESPACE}:move-row-down`]: this.editorCommand(editorCtrler => { 105 | editorCtrler.moveRowDown(); 106 | }), 107 | [`${NAMESPACE}:insert-column`]: this.editorCommand(editorCtrler => { 108 | editorCtrler.insertColumn(); 109 | }), 110 | [`${NAMESPACE}:delete-column`]: this.editorCommand(editorCtrler => { 111 | editorCtrler.deleteColumn(); 112 | }), 113 | [`${NAMESPACE}:move-column-left`]: this.editorCommand(editorCtrler => { 114 | editorCtrler.moveColumnLeft(); 115 | }), 116 | [`${NAMESPACE}:move-column-right`]: this.editorCommand(editorCtrler => { 117 | editorCtrler.moveColumnRight(); 118 | }) 119 | })); 120 | } 121 | 122 | addEditor(editor) { 123 | const editorCtrler = new EditorController(editor); 124 | this.editorCtrlers.set(editor.element, editorCtrler); 125 | } 126 | 127 | removeEditor(editor) { 128 | this.editorCtrlers.delete(editor.element); 129 | } 130 | 131 | toggleFormatOnSave() { 132 | const formatOnSave = atom.config.get(`${NAMESPACE}.formatOnSave`); 133 | atom.config.set(`${NAMESPACE}.formatOnSave`, !formatOnSave); 134 | atom.notifications.addInfo("markdown-table-editor", { 135 | detail: `"Format On Save" is turned ${!formatOnSave ? "on" : "off"}` 136 | }); 137 | } 138 | 139 | switchFormatType() { 140 | const formatType = atom.config.get(`${NAMESPACE}.formatType`); 141 | const i = FORMAT_TYPES.indexOf(formatType); 142 | const newFormatType = FORMAT_TYPES[i + 1 > FORMAT_TYPES.length - 1 ? 0 : i + 1]; 143 | atom.config.set(`${NAMESPACE}.formatType`, newFormatType); 144 | atom.notifications.addInfo("markdown-table-editor", { 145 | detail: `"Format Type" is switched to "${FORMAT_TYPE_NAMES[newFormatType]}"` 146 | }); 147 | } 148 | 149 | setFormatType(type) { 150 | atom.config.set(`${NAMESPACE}.formatType`, type); 151 | atom.notifications.addInfo("markdown-table-editor", { 152 | detail: `"Format Type" is set to "${FORMAT_TYPE_NAMES[type]}"` 153 | }); 154 | } 155 | 156 | editorCommand(callback) { 157 | return event => { 158 | if (this.editorCtrlers.has(event.currentTarget)) { 159 | callback(this.editorCtrlers.get(event.currentTarget)); 160 | } 161 | }; 162 | } 163 | 164 | destroy() { 165 | this.subscriptions.dispose(); 166 | 167 | for (const editorCtrler of this.editorCtrlers.values()) { 168 | editorCtrler.destroy(); 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /lib/editor-controller.js: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable } from "atom"; 2 | import { TableEditor, options, Alignment } from "@susisu/mte-kernel"; 3 | 4 | import TextEditorInterface from "./text-editor-interface.js"; 5 | 6 | const NAMESPACE = "markdown-table-editor"; 7 | const ACTIVE_CLASS = "markdown-table-editor-active"; 8 | 9 | export default class EditorController { 10 | constructor(editor) { 11 | this.editor = editor; 12 | this.editorIntf = new TextEditorInterface(this.editor, atom.config.get(`${NAMESPACE}.scopes`)); 13 | this.tableEditor = new TableEditor(this.editorIntf); 14 | 15 | this.updateActiveState(); 16 | 17 | // event subscriptions 18 | this.subscriptions = new CompositeDisposable(); 19 | 20 | // editor 21 | this.subscriptions.add(this.editor.onDidChangeGrammar(() => { 22 | this.updateActiveState(); 23 | })); 24 | this.subscriptions.add(this.editor.onDidAddCursor(() => { 25 | this.updateActiveState(); 26 | })); 27 | this.subscriptions.add(this.editor.onDidRemoveCursor(() => { 28 | this.updateActiveState(); 29 | })); 30 | this.subscriptions.add(this.editor.onDidChangeCursorPosition(event => { 31 | if (!this.editorIntf.transaction 32 | && event.newBufferPosition.row !== event.oldBufferPosition.row) { 33 | this.updateActiveState(); 34 | } 35 | })); 36 | this.subscriptions.add(this.editor.onDidStopChanging(() => { 37 | if (!this.editorIntf.transaction) { 38 | this.updateActiveState(); 39 | } 40 | })); 41 | this.subscriptions.add(this.editorIntf.onDidFinishTransaction(() => { 42 | this.updateActiveState(); 43 | })); 44 | this.subscriptions.add(this.editor.getBuffer().onWillSave(() => { 45 | if (atom.config.get(`${NAMESPACE}.formatOnSave`)) { 46 | this.formatAll(); 47 | } 48 | })); 49 | 50 | // config 51 | this.subscriptions.add(atom.config.observe(`${NAMESPACE}.scopes`, scopes => { 52 | this.editorIntf.scopes = scopes; 53 | this.updateActiveState(); 54 | })); 55 | } 56 | 57 | updateActiveState() { 58 | const isActive = !this.editor.hasMultipleCursors() 59 | && this.tableEditor.cursorIsInTable(this.getOptions()); 60 | if (isActive) { 61 | this.editor.element.classList.add(ACTIVE_CLASS); 62 | } 63 | else { 64 | this.editor.element.classList.remove(ACTIVE_CLASS); 65 | this.tableEditor.resetSmartCursor(); 66 | } 67 | } 68 | 69 | getOptions() { 70 | const configOpt = { 71 | scope: this.editor.scopeDescriptorForBufferPosition(this.editor.getCursorBufferPosition()) 72 | }; 73 | return options({ 74 | leftMarginChars : new Set(atom.config.get(`${NAMESPACE}.leftMarginChars`, configOpt)), 75 | formatType : atom.config.get(`${NAMESPACE}.formatType`, configOpt), 76 | minDelimiterWidth: atom.config.get(`${NAMESPACE}.minDelimiterWidth`, configOpt), 77 | defaultAlignment : atom.config.get(`${NAMESPACE}.defaultAlignment`, configOpt), 78 | headerAlignment : atom.config.get(`${NAMESPACE}.headerAlignment`, configOpt), 79 | smartCursor : atom.config.get(`${NAMESPACE}.smartCursor`, configOpt), 80 | textWidthOptions : { 81 | normalize : atom.config.get(`${NAMESPACE}.normalize`, configOpt), 82 | wideChars : new Set(atom.config.get(`${NAMESPACE}.wideChars`, configOpt)), 83 | narrowChars : new Set(atom.config.get(`${NAMESPACE}.narrowChars`, configOpt)), 84 | ambiguousAsWide: atom.config.get(`${NAMESPACE}.ambiguousAsWide`, configOpt) 85 | } 86 | }); 87 | } 88 | 89 | format() { 90 | this.tableEditor.format(this.getOptions()); 91 | } 92 | 93 | formatAll() { 94 | this.tableEditor.formatAll(this.getOptions()); 95 | } 96 | 97 | escape() { 98 | this.tableEditor.escape(this.getOptions()); 99 | } 100 | 101 | alignLeft() { 102 | this.tableEditor.alignColumn(Alignment.LEFT, this.getOptions()); 103 | } 104 | 105 | alignRight() { 106 | this.tableEditor.alignColumn(Alignment.RIGHT, this.getOptions()); 107 | } 108 | 109 | alignCenter() { 110 | this.tableEditor.alignColumn(Alignment.CENTER, this.getOptions()); 111 | } 112 | 113 | alignNone() { 114 | this.tableEditor.alignColumn(Alignment.NONE, this.getOptions()); 115 | } 116 | 117 | selectCell() { 118 | this.tableEditor.selectCell(this.getOptions()); 119 | } 120 | 121 | moveLeft() { 122 | this.tableEditor.moveFocus(0, -1, this.getOptions()); 123 | } 124 | 125 | moveRight() { 126 | this.tableEditor.moveFocus(0, 1, this.getOptions()); 127 | } 128 | 129 | moveUp() { 130 | this.tableEditor.moveFocus(-1, 0, this.getOptions()); 131 | } 132 | 133 | moveDown() { 134 | this.tableEditor.moveFocus(1, 0, this.getOptions()); 135 | } 136 | 137 | nextCell() { 138 | this.tableEditor.nextCell(this.getOptions()); 139 | } 140 | 141 | previousCell() { 142 | this.tableEditor.previousCell(this.getOptions()); 143 | } 144 | 145 | nextRow() { 146 | this.tableEditor.nextRow(this.getOptions()); 147 | } 148 | 149 | insertRow() { 150 | this.tableEditor.insertRow(this.getOptions()); 151 | } 152 | 153 | deleteRow() { 154 | this.tableEditor.deleteRow(this.getOptions()); 155 | } 156 | 157 | moveRowUp() { 158 | this.tableEditor.moveRow(-1, this.getOptions()); 159 | } 160 | 161 | moveRowDown() { 162 | this.tableEditor.moveRow(1, this.getOptions()); 163 | } 164 | 165 | insertColumn() { 166 | this.tableEditor.insertColumn(this.getOptions()); 167 | } 168 | 169 | deleteColumn() { 170 | this.tableEditor.deleteColumn(this.getOptions()); 171 | } 172 | 173 | moveColumnLeft() { 174 | this.tableEditor.moveColumn(-1, this.getOptions()); 175 | } 176 | 177 | moveColumnRight() { 178 | this.tableEditor.moveColumn(1, this.getOptions()); 179 | } 180 | 181 | destroy() { 182 | this.subscriptions.dispose(); 183 | this.editorIntf.destroy(); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /lib/markdown-table-editor.js: -------------------------------------------------------------------------------- 1 | import Controller from "./controller.js"; 2 | 3 | const NAMESPACE = "markdown-table-editor"; 4 | 5 | class MarkdownTableEditor { 6 | constructor() { 7 | this.controller = null; 8 | } 9 | 10 | activate() { 11 | this.controller = new Controller(); 12 | // migrate old configurations 13 | const grammars = atom.config.get(`${NAMESPACE}.grammars`); 14 | if (grammars !== undefined) { 15 | atom.config.set(`${NAMESPACE}.scopes`, grammars); 16 | atom.config.unset(`${NAMESPACE}.grammars`); 17 | } 18 | const minimumContentWidth = atom.config.get(`${NAMESPACE}.minimumContentWidth`); 19 | if (minimumContentWidth !== undefined) { 20 | atom.config.set(`${NAMESPACE}.minDelimiterWidth`, minimumContentWidth); 21 | atom.config.unset(`${NAMESPACE}.minimumContentWidth`); 22 | } 23 | const eawAmbiguousAsWide = atom.config.get(`${NAMESPACE}.eawAmbiguousAsWide`); 24 | if (eawAmbiguousAsWide !== undefined) { 25 | atom.config.set(`${NAMESPACE}.ambiguousAsWide`, eawAmbiguousAsWide); 26 | atom.config.unset(`${NAMESPACE}.eawAmbiguousAsWide`); 27 | } 28 | const alwaysWideChars = atom.config.get(`${NAMESPACE}.alwaysWideChars`); 29 | if (alwaysWideChars !== undefined) { 30 | atom.config.set(`${NAMESPACE}.wideChars`, alwaysWideChars); 31 | atom.config.unset(`${NAMESPACE}.alwaysWideChars`); 32 | } 33 | const alwaysNarrowChars = atom.config.get(`${NAMESPACE}.alwaysNarrowChars`); 34 | if (alwaysNarrowChars !== undefined) { 35 | atom.config.set(`${NAMESPACE}.narrowChars`, alwaysNarrowChars); 36 | atom.config.unset(`${NAMESPACE}.alwaysNarrowChars`); 37 | } 38 | } 39 | 40 | deactivate() { 41 | this.controller.destroy(); 42 | } 43 | 44 | serialize() { 45 | } 46 | } 47 | 48 | module.exports = new MarkdownTableEditor(); 49 | -------------------------------------------------------------------------------- /lib/text-editor-interface.js: -------------------------------------------------------------------------------- 1 | import { Emitter } from "atom"; 2 | import { Point, ITextEditor } from "@susisu/mte-kernel"; 3 | 4 | export default class TextEditorInterface extends ITextEditor { 5 | constructor(textEditor, scopes) { 6 | super(); 7 | this.textEditor = textEditor; 8 | this.textBuffer = textEditor.getBuffer(); 9 | this.scopes = scopes; 10 | this.transaction = false; 11 | this.emitter = new Emitter(); 12 | } 13 | 14 | getCursorPosition() { 15 | const _pos = this.textEditor.getCursorBufferPosition(); 16 | return new Point(_pos.row, _pos.column); 17 | } 18 | 19 | setCursorPosition(pos) { 20 | this.textEditor.setCursorBufferPosition([pos.row, pos.column]); 21 | } 22 | 23 | setSelectionRange(range) { 24 | this.textEditor.setSelectedBufferRange([ 25 | [range.start.row, range.start.column], 26 | [range.end.row, range.end.column] 27 | ]); 28 | } 29 | 30 | getLastRow() { 31 | return this.textBuffer.getLastRow(); 32 | } 33 | 34 | acceptsTableEdit(row) { 35 | const sd = this.textEditor.scopeDescriptorForBufferPosition([row, 0]).getScopesArray(); 36 | for (const scope of this.scopes) { 37 | if (sd.indexOf(scope) >= 0) { 38 | return true; 39 | } 40 | } 41 | return false; 42 | } 43 | 44 | getLine(row) { 45 | return this.textBuffer.lineForRow(row); 46 | } 47 | 48 | insertLine(row, line) { 49 | const lastRow = this.textBuffer.getLastRow(); 50 | if (row > lastRow) { 51 | const le = this.textBuffer.lineEndingForRow(lastRow); 52 | this.textBuffer.append("\n" + line + le, { normalizeLineEndings: true }); 53 | } 54 | else { 55 | this.textBuffer.insert([row, 0], line + "\n", { normalizeLineEndings: true }); 56 | } 57 | } 58 | 59 | deleteLine(row) { 60 | this.textBuffer.deleteRow(row); 61 | } 62 | 63 | replaceLines(startRow, endRow, lines) { 64 | const le = this.textBuffer.lineEndingForRow(endRow - 1); 65 | this.textBuffer.setTextInRange( 66 | [[startRow, 0], [endRow, 0]], 67 | lines.join("\n") + le, 68 | { normalizeLineEndings: true } 69 | ); 70 | } 71 | 72 | transact(func) { 73 | this.transaction = true; 74 | this.textBuffer.transact(() => { func(); }); 75 | this.transaction = false; 76 | this.emitter.emit("did-finish-transaction"); 77 | } 78 | 79 | onDidFinishTransaction(func) { 80 | return this.emitter.on("did-finish-transaction", func); 81 | } 82 | 83 | destroy() { 84 | this.emitter.dispose(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /menus/markdown-table-editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "menu": [ 3 | { 4 | "label": "Packages", 5 | "submenu": [ 6 | { 7 | "label": "Markdown Table Editor", 8 | "submenu": [ 9 | { 10 | "label": "Format", 11 | "command": "markdown-table-editor:format" 12 | }, 13 | { 14 | "type": "separator" 15 | }, 16 | { 17 | "label": "Align Left", 18 | "command": "markdown-table-editor:align-left" 19 | }, 20 | { 21 | "label": "Align Right", 22 | "command": "markdown-table-editor:align-right" 23 | }, 24 | { 25 | "label": "Align Center", 26 | "command": "markdown-table-editor:align-center" 27 | }, 28 | { 29 | "label": "Align Default", 30 | "command": "markdown-table-editor:align-default" 31 | }, 32 | { 33 | "type": "separator" 34 | }, 35 | { 36 | "label": "Select Cell", 37 | "command": "markdown-table-editor:select-cell" 38 | }, 39 | { 40 | "type": "separator" 41 | }, 42 | { 43 | "label": "Insert Row", 44 | "command": "markdown-table-editor:insert-row" 45 | }, 46 | { 47 | "label": "Delete Row", 48 | "command": "markdown-table-editor:delete-row" 49 | }, 50 | { 51 | "label": "Insert Column", 52 | "command": "markdown-table-editor:insert-column" 53 | }, 54 | { 55 | "label": "Delete Column", 56 | "command": "markdown-table-editor:delete-column" 57 | } 58 | ] 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-table-editor", 3 | "version": "1.1.3", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", 10 | "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.0.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", 19 | "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | }, 26 | "dependencies": { 27 | "ansi-styles": { 28 | "version": "3.2.1", 29 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 30 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 31 | "dev": true, 32 | "requires": { 33 | "color-convert": "^1.9.0" 34 | } 35 | }, 36 | "chalk": { 37 | "version": "2.4.2", 38 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 39 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 40 | "dev": true, 41 | "requires": { 42 | "ansi-styles": "^3.2.1", 43 | "escape-string-regexp": "^1.0.5", 44 | "supports-color": "^5.3.0" 45 | } 46 | }, 47 | "js-tokens": { 48 | "version": "4.0.0", 49 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 50 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 51 | "dev": true 52 | }, 53 | "supports-color": { 54 | "version": "5.5.0", 55 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 56 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 57 | "dev": true, 58 | "requires": { 59 | "has-flag": "^3.0.0" 60 | } 61 | } 62 | } 63 | }, 64 | "@susisu/mte-kernel": { 65 | "version": "2.1.1", 66 | "resolved": "https://registry.npmjs.org/@susisu/mte-kernel/-/mte-kernel-2.1.1.tgz", 67 | "integrity": "sha512-i2lucPD0BOUNIY6P0MGIUbJ/piV8iNzwB8QU1fdkRLls85rq8NJa75oeZVWo2PLrUWjN64+3oD85kZFsx3ovyA==", 68 | "requires": { 69 | "meaw": "^5.0.0" 70 | } 71 | }, 72 | "acorn": { 73 | "version": "6.1.1", 74 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", 75 | "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", 76 | "dev": true 77 | }, 78 | "acorn-jsx": { 79 | "version": "5.0.1", 80 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", 81 | "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", 82 | "dev": true 83 | }, 84 | "ajv": { 85 | "version": "6.10.0", 86 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", 87 | "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", 88 | "dev": true, 89 | "requires": { 90 | "fast-deep-equal": "^2.0.1", 91 | "fast-json-stable-stringify": "^2.0.0", 92 | "json-schema-traverse": "^0.4.1", 93 | "uri-js": "^4.2.2" 94 | } 95 | }, 96 | "ansi-escapes": { 97 | "version": "3.2.0", 98 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", 99 | "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", 100 | "dev": true 101 | }, 102 | "ansi-regex": { 103 | "version": "2.1.1", 104 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 105 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 106 | }, 107 | "ansi-styles": { 108 | "version": "2.2.1", 109 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 110 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" 111 | }, 112 | "argparse": { 113 | "version": "1.0.10", 114 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 115 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 116 | "dev": true, 117 | "requires": { 118 | "sprintf-js": "~1.0.2" 119 | } 120 | }, 121 | "astral-regex": { 122 | "version": "1.0.0", 123 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 124 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", 125 | "dev": true 126 | }, 127 | "atom-babel6-transpiler": { 128 | "version": "1.2.0", 129 | "resolved": "https://registry.npmjs.org/atom-babel6-transpiler/-/atom-babel6-transpiler-1.2.0.tgz", 130 | "integrity": "sha512-lZucrjVyRtPAPPJxvICCEBsAC1qn48wUHaIlieriWCXTXLqtLC2PvkQU7vNvU2w1eZ7tw9m0lojZ8PbpVyWTvg==", 131 | "requires": { 132 | "babel-core": "6.x" 133 | } 134 | }, 135 | "babel-code-frame": { 136 | "version": "6.26.0", 137 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 138 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 139 | "requires": { 140 | "chalk": "^1.1.3", 141 | "esutils": "^2.0.2", 142 | "js-tokens": "^3.0.2" 143 | } 144 | }, 145 | "babel-core": { 146 | "version": "6.26.3", 147 | "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", 148 | "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", 149 | "requires": { 150 | "babel-code-frame": "^6.26.0", 151 | "babel-generator": "^6.26.0", 152 | "babel-helpers": "^6.24.1", 153 | "babel-messages": "^6.23.0", 154 | "babel-register": "^6.26.0", 155 | "babel-runtime": "^6.26.0", 156 | "babel-template": "^6.26.0", 157 | "babel-traverse": "^6.26.0", 158 | "babel-types": "^6.26.0", 159 | "babylon": "^6.18.0", 160 | "convert-source-map": "^1.5.1", 161 | "debug": "^2.6.9", 162 | "json5": "^0.5.1", 163 | "lodash": "^4.17.4", 164 | "minimatch": "^3.0.4", 165 | "path-is-absolute": "^1.0.1", 166 | "private": "^0.1.8", 167 | "slash": "^1.0.0", 168 | "source-map": "^0.5.7" 169 | } 170 | }, 171 | "babel-generator": { 172 | "version": "6.26.1", 173 | "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", 174 | "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", 175 | "requires": { 176 | "babel-messages": "^6.23.0", 177 | "babel-runtime": "^6.26.0", 178 | "babel-types": "^6.26.0", 179 | "detect-indent": "^4.0.0", 180 | "jsesc": "^1.3.0", 181 | "lodash": "^4.17.4", 182 | "source-map": "^0.5.7", 183 | "trim-right": "^1.0.1" 184 | } 185 | }, 186 | "babel-helpers": { 187 | "version": "6.24.1", 188 | "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", 189 | "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", 190 | "requires": { 191 | "babel-runtime": "^6.22.0", 192 | "babel-template": "^6.24.1" 193 | } 194 | }, 195 | "babel-messages": { 196 | "version": "6.23.0", 197 | "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", 198 | "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", 199 | "requires": { 200 | "babel-runtime": "^6.22.0" 201 | } 202 | }, 203 | "babel-plugin-transform-es2015-modules-commonjs": { 204 | "version": "6.26.2", 205 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", 206 | "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", 207 | "requires": { 208 | "babel-plugin-transform-strict-mode": "^6.24.1", 209 | "babel-runtime": "^6.26.0", 210 | "babel-template": "^6.26.0", 211 | "babel-types": "^6.26.0" 212 | } 213 | }, 214 | "babel-plugin-transform-strict-mode": { 215 | "version": "6.24.1", 216 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", 217 | "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", 218 | "requires": { 219 | "babel-runtime": "^6.22.0", 220 | "babel-types": "^6.24.1" 221 | } 222 | }, 223 | "babel-register": { 224 | "version": "6.26.0", 225 | "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", 226 | "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", 227 | "requires": { 228 | "babel-core": "^6.26.0", 229 | "babel-runtime": "^6.26.0", 230 | "core-js": "^2.5.0", 231 | "home-or-tmp": "^2.0.0", 232 | "lodash": "^4.17.4", 233 | "mkdirp": "^0.5.1", 234 | "source-map-support": "^0.4.15" 235 | } 236 | }, 237 | "babel-runtime": { 238 | "version": "6.26.0", 239 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 240 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 241 | "requires": { 242 | "core-js": "^2.4.0", 243 | "regenerator-runtime": "^0.11.0" 244 | } 245 | }, 246 | "babel-template": { 247 | "version": "6.26.0", 248 | "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", 249 | "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", 250 | "requires": { 251 | "babel-runtime": "^6.26.0", 252 | "babel-traverse": "^6.26.0", 253 | "babel-types": "^6.26.0", 254 | "babylon": "^6.18.0", 255 | "lodash": "^4.17.4" 256 | } 257 | }, 258 | "babel-traverse": { 259 | "version": "6.26.0", 260 | "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", 261 | "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", 262 | "requires": { 263 | "babel-code-frame": "^6.26.0", 264 | "babel-messages": "^6.23.0", 265 | "babel-runtime": "^6.26.0", 266 | "babel-types": "^6.26.0", 267 | "babylon": "^6.18.0", 268 | "debug": "^2.6.8", 269 | "globals": "^9.18.0", 270 | "invariant": "^2.2.2", 271 | "lodash": "^4.17.4" 272 | } 273 | }, 274 | "babel-types": { 275 | "version": "6.26.0", 276 | "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", 277 | "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", 278 | "requires": { 279 | "babel-runtime": "^6.26.0", 280 | "esutils": "^2.0.2", 281 | "lodash": "^4.17.4", 282 | "to-fast-properties": "^1.0.3" 283 | } 284 | }, 285 | "babylon": { 286 | "version": "6.18.0", 287 | "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", 288 | "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" 289 | }, 290 | "balanced-match": { 291 | "version": "1.0.0", 292 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 293 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 294 | }, 295 | "brace-expansion": { 296 | "version": "1.1.11", 297 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 298 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 299 | "requires": { 300 | "balanced-match": "^1.0.0", 301 | "concat-map": "0.0.1" 302 | } 303 | }, 304 | "callsites": { 305 | "version": "3.1.0", 306 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 307 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 308 | "dev": true 309 | }, 310 | "chalk": { 311 | "version": "1.1.3", 312 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 313 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 314 | "requires": { 315 | "ansi-styles": "^2.2.1", 316 | "escape-string-regexp": "^1.0.2", 317 | "has-ansi": "^2.0.0", 318 | "strip-ansi": "^3.0.0", 319 | "supports-color": "^2.0.0" 320 | } 321 | }, 322 | "chardet": { 323 | "version": "0.7.0", 324 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 325 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", 326 | "dev": true 327 | }, 328 | "cli-cursor": { 329 | "version": "2.1.0", 330 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 331 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 332 | "dev": true, 333 | "requires": { 334 | "restore-cursor": "^2.0.0" 335 | } 336 | }, 337 | "cli-width": { 338 | "version": "2.2.0", 339 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 340 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 341 | "dev": true 342 | }, 343 | "color-convert": { 344 | "version": "1.9.3", 345 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 346 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 347 | "dev": true, 348 | "requires": { 349 | "color-name": "1.1.3" 350 | } 351 | }, 352 | "color-name": { 353 | "version": "1.1.3", 354 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 355 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 356 | "dev": true 357 | }, 358 | "concat-map": { 359 | "version": "0.0.1", 360 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 361 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 362 | }, 363 | "convert-source-map": { 364 | "version": "1.6.0", 365 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", 366 | "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", 367 | "requires": { 368 | "safe-buffer": "~5.1.1" 369 | } 370 | }, 371 | "core-js": { 372 | "version": "2.5.6", 373 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", 374 | "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==" 375 | }, 376 | "cross-spawn": { 377 | "version": "6.0.5", 378 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 379 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 380 | "dev": true, 381 | "requires": { 382 | "nice-try": "^1.0.4", 383 | "path-key": "^2.0.1", 384 | "semver": "^5.5.0", 385 | "shebang-command": "^1.2.0", 386 | "which": "^1.2.9" 387 | } 388 | }, 389 | "debug": { 390 | "version": "2.6.9", 391 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 392 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 393 | "requires": { 394 | "ms": "2.0.0" 395 | } 396 | }, 397 | "deep-is": { 398 | "version": "0.1.3", 399 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 400 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 401 | "dev": true 402 | }, 403 | "detect-indent": { 404 | "version": "4.0.0", 405 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", 406 | "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", 407 | "requires": { 408 | "repeating": "^2.0.0" 409 | } 410 | }, 411 | "doctrine": { 412 | "version": "3.0.0", 413 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 414 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 415 | "dev": true, 416 | "requires": { 417 | "esutils": "^2.0.2" 418 | } 419 | }, 420 | "emoji-regex": { 421 | "version": "7.0.3", 422 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 423 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 424 | "dev": true 425 | }, 426 | "escape-string-regexp": { 427 | "version": "1.0.5", 428 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 429 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 430 | }, 431 | "eslint": { 432 | "version": "5.16.0", 433 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", 434 | "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", 435 | "dev": true, 436 | "requires": { 437 | "@babel/code-frame": "^7.0.0", 438 | "ajv": "^6.9.1", 439 | "chalk": "^2.1.0", 440 | "cross-spawn": "^6.0.5", 441 | "debug": "^4.0.1", 442 | "doctrine": "^3.0.0", 443 | "eslint-scope": "^4.0.3", 444 | "eslint-utils": "^1.3.1", 445 | "eslint-visitor-keys": "^1.0.0", 446 | "espree": "^5.0.1", 447 | "esquery": "^1.0.1", 448 | "esutils": "^2.0.2", 449 | "file-entry-cache": "^5.0.1", 450 | "functional-red-black-tree": "^1.0.1", 451 | "glob": "^7.1.2", 452 | "globals": "^11.7.0", 453 | "ignore": "^4.0.6", 454 | "import-fresh": "^3.0.0", 455 | "imurmurhash": "^0.1.4", 456 | "inquirer": "^6.2.2", 457 | "js-yaml": "^3.13.0", 458 | "json-stable-stringify-without-jsonify": "^1.0.1", 459 | "levn": "^0.3.0", 460 | "lodash": "^4.17.11", 461 | "minimatch": "^3.0.4", 462 | "mkdirp": "^0.5.1", 463 | "natural-compare": "^1.4.0", 464 | "optionator": "^0.8.2", 465 | "path-is-inside": "^1.0.2", 466 | "progress": "^2.0.0", 467 | "regexpp": "^2.0.1", 468 | "semver": "^5.5.1", 469 | "strip-ansi": "^4.0.0", 470 | "strip-json-comments": "^2.0.1", 471 | "table": "^5.2.3", 472 | "text-table": "^0.2.0" 473 | }, 474 | "dependencies": { 475 | "ansi-regex": { 476 | "version": "3.0.0", 477 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 478 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 479 | "dev": true 480 | }, 481 | "ansi-styles": { 482 | "version": "3.2.1", 483 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 484 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 485 | "dev": true, 486 | "requires": { 487 | "color-convert": "^1.9.0" 488 | } 489 | }, 490 | "chalk": { 491 | "version": "2.4.2", 492 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 493 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 494 | "dev": true, 495 | "requires": { 496 | "ansi-styles": "^3.2.1", 497 | "escape-string-regexp": "^1.0.5", 498 | "supports-color": "^5.3.0" 499 | } 500 | }, 501 | "debug": { 502 | "version": "4.1.1", 503 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 504 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 505 | "dev": true, 506 | "requires": { 507 | "ms": "^2.1.1" 508 | } 509 | }, 510 | "globals": { 511 | "version": "11.12.0", 512 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 513 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 514 | "dev": true 515 | }, 516 | "ms": { 517 | "version": "2.1.1", 518 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 519 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 520 | "dev": true 521 | }, 522 | "strip-ansi": { 523 | "version": "4.0.0", 524 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 525 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 526 | "dev": true, 527 | "requires": { 528 | "ansi-regex": "^3.0.0" 529 | } 530 | }, 531 | "supports-color": { 532 | "version": "5.5.0", 533 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 534 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 535 | "dev": true, 536 | "requires": { 537 | "has-flag": "^3.0.0" 538 | } 539 | } 540 | } 541 | }, 542 | "eslint-scope": { 543 | "version": "4.0.3", 544 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", 545 | "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", 546 | "dev": true, 547 | "requires": { 548 | "esrecurse": "^4.1.0", 549 | "estraverse": "^4.1.1" 550 | } 551 | }, 552 | "eslint-utils": { 553 | "version": "1.3.1", 554 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", 555 | "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", 556 | "dev": true 557 | }, 558 | "eslint-visitor-keys": { 559 | "version": "1.0.0", 560 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", 561 | "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", 562 | "dev": true 563 | }, 564 | "espree": { 565 | "version": "5.0.1", 566 | "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", 567 | "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", 568 | "dev": true, 569 | "requires": { 570 | "acorn": "^6.0.7", 571 | "acorn-jsx": "^5.0.0", 572 | "eslint-visitor-keys": "^1.0.0" 573 | } 574 | }, 575 | "esprima": { 576 | "version": "4.0.1", 577 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 578 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 579 | "dev": true 580 | }, 581 | "esquery": { 582 | "version": "1.0.1", 583 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", 584 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", 585 | "dev": true, 586 | "requires": { 587 | "estraverse": "^4.0.0" 588 | } 589 | }, 590 | "esrecurse": { 591 | "version": "4.2.1", 592 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 593 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 594 | "dev": true, 595 | "requires": { 596 | "estraverse": "^4.1.0" 597 | } 598 | }, 599 | "estraverse": { 600 | "version": "4.2.0", 601 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 602 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 603 | "dev": true 604 | }, 605 | "esutils": { 606 | "version": "2.0.2", 607 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 608 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" 609 | }, 610 | "external-editor": { 611 | "version": "3.0.3", 612 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", 613 | "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", 614 | "dev": true, 615 | "requires": { 616 | "chardet": "^0.7.0", 617 | "iconv-lite": "^0.4.24", 618 | "tmp": "^0.0.33" 619 | } 620 | }, 621 | "fast-deep-equal": { 622 | "version": "2.0.1", 623 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 624 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", 625 | "dev": true 626 | }, 627 | "fast-json-stable-stringify": { 628 | "version": "2.0.0", 629 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 630 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", 631 | "dev": true 632 | }, 633 | "fast-levenshtein": { 634 | "version": "2.0.6", 635 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 636 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 637 | "dev": true 638 | }, 639 | "figures": { 640 | "version": "2.0.0", 641 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 642 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 643 | "dev": true, 644 | "requires": { 645 | "escape-string-regexp": "^1.0.5" 646 | } 647 | }, 648 | "file-entry-cache": { 649 | "version": "5.0.1", 650 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 651 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", 652 | "dev": true, 653 | "requires": { 654 | "flat-cache": "^2.0.1" 655 | } 656 | }, 657 | "flat-cache": { 658 | "version": "2.0.1", 659 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", 660 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", 661 | "dev": true, 662 | "requires": { 663 | "flatted": "^2.0.0", 664 | "rimraf": "2.6.3", 665 | "write": "1.0.3" 666 | } 667 | }, 668 | "flatted": { 669 | "version": "2.0.0", 670 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", 671 | "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", 672 | "dev": true 673 | }, 674 | "fs.realpath": { 675 | "version": "1.0.0", 676 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 677 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 678 | "dev": true 679 | }, 680 | "functional-red-black-tree": { 681 | "version": "1.0.1", 682 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 683 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 684 | "dev": true 685 | }, 686 | "glob": { 687 | "version": "7.1.4", 688 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 689 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 690 | "dev": true, 691 | "requires": { 692 | "fs.realpath": "^1.0.0", 693 | "inflight": "^1.0.4", 694 | "inherits": "2", 695 | "minimatch": "^3.0.4", 696 | "once": "^1.3.0", 697 | "path-is-absolute": "^1.0.0" 698 | } 699 | }, 700 | "globals": { 701 | "version": "9.18.0", 702 | "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", 703 | "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" 704 | }, 705 | "has-ansi": { 706 | "version": "2.0.0", 707 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 708 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 709 | "requires": { 710 | "ansi-regex": "^2.0.0" 711 | } 712 | }, 713 | "has-flag": { 714 | "version": "3.0.0", 715 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 716 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 717 | "dev": true 718 | }, 719 | "home-or-tmp": { 720 | "version": "2.0.0", 721 | "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", 722 | "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", 723 | "requires": { 724 | "os-homedir": "^1.0.0", 725 | "os-tmpdir": "^1.0.1" 726 | } 727 | }, 728 | "iconv-lite": { 729 | "version": "0.4.24", 730 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 731 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 732 | "dev": true, 733 | "requires": { 734 | "safer-buffer": ">= 2.1.2 < 3" 735 | } 736 | }, 737 | "ignore": { 738 | "version": "4.0.6", 739 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 740 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 741 | "dev": true 742 | }, 743 | "import-fresh": { 744 | "version": "3.0.0", 745 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", 746 | "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", 747 | "dev": true, 748 | "requires": { 749 | "parent-module": "^1.0.0", 750 | "resolve-from": "^4.0.0" 751 | } 752 | }, 753 | "imurmurhash": { 754 | "version": "0.1.4", 755 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 756 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 757 | "dev": true 758 | }, 759 | "inflight": { 760 | "version": "1.0.6", 761 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 762 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 763 | "dev": true, 764 | "requires": { 765 | "once": "^1.3.0", 766 | "wrappy": "1" 767 | } 768 | }, 769 | "inherits": { 770 | "version": "2.0.3", 771 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 772 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 773 | "dev": true 774 | }, 775 | "inquirer": { 776 | "version": "6.3.1", 777 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", 778 | "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", 779 | "dev": true, 780 | "requires": { 781 | "ansi-escapes": "^3.2.0", 782 | "chalk": "^2.4.2", 783 | "cli-cursor": "^2.1.0", 784 | "cli-width": "^2.0.0", 785 | "external-editor": "^3.0.3", 786 | "figures": "^2.0.0", 787 | "lodash": "^4.17.11", 788 | "mute-stream": "0.0.7", 789 | "run-async": "^2.2.0", 790 | "rxjs": "^6.4.0", 791 | "string-width": "^2.1.0", 792 | "strip-ansi": "^5.1.0", 793 | "through": "^2.3.6" 794 | }, 795 | "dependencies": { 796 | "ansi-regex": { 797 | "version": "4.1.0", 798 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 799 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 800 | "dev": true 801 | }, 802 | "ansi-styles": { 803 | "version": "3.2.1", 804 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 805 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 806 | "dev": true, 807 | "requires": { 808 | "color-convert": "^1.9.0" 809 | } 810 | }, 811 | "chalk": { 812 | "version": "2.4.2", 813 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 814 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 815 | "dev": true, 816 | "requires": { 817 | "ansi-styles": "^3.2.1", 818 | "escape-string-regexp": "^1.0.5", 819 | "supports-color": "^5.3.0" 820 | } 821 | }, 822 | "strip-ansi": { 823 | "version": "5.2.0", 824 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 825 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 826 | "dev": true, 827 | "requires": { 828 | "ansi-regex": "^4.1.0" 829 | } 830 | }, 831 | "supports-color": { 832 | "version": "5.5.0", 833 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 834 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 835 | "dev": true, 836 | "requires": { 837 | "has-flag": "^3.0.0" 838 | } 839 | } 840 | } 841 | }, 842 | "invariant": { 843 | "version": "2.2.4", 844 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", 845 | "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", 846 | "requires": { 847 | "loose-envify": "^1.0.0" 848 | } 849 | }, 850 | "is-finite": { 851 | "version": "1.0.2", 852 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", 853 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", 854 | "requires": { 855 | "number-is-nan": "^1.0.0" 856 | } 857 | }, 858 | "is-fullwidth-code-point": { 859 | "version": "2.0.0", 860 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 861 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 862 | "dev": true 863 | }, 864 | "is-promise": { 865 | "version": "2.1.0", 866 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 867 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", 868 | "dev": true 869 | }, 870 | "isexe": { 871 | "version": "2.0.0", 872 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 873 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 874 | "dev": true 875 | }, 876 | "js-tokens": { 877 | "version": "3.0.2", 878 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 879 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" 880 | }, 881 | "js-yaml": { 882 | "version": "3.13.1", 883 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 884 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 885 | "dev": true, 886 | "requires": { 887 | "argparse": "^1.0.7", 888 | "esprima": "^4.0.0" 889 | } 890 | }, 891 | "jsesc": { 892 | "version": "1.3.0", 893 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", 894 | "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" 895 | }, 896 | "json-schema-traverse": { 897 | "version": "0.4.1", 898 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 899 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 900 | "dev": true 901 | }, 902 | "json-stable-stringify-without-jsonify": { 903 | "version": "1.0.1", 904 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 905 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 906 | "dev": true 907 | }, 908 | "json5": { 909 | "version": "0.5.1", 910 | "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", 911 | "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" 912 | }, 913 | "levn": { 914 | "version": "0.3.0", 915 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 916 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 917 | "dev": true, 918 | "requires": { 919 | "prelude-ls": "~1.1.2", 920 | "type-check": "~0.3.2" 921 | } 922 | }, 923 | "lodash": { 924 | "version": "4.17.11", 925 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 926 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 927 | }, 928 | "loose-envify": { 929 | "version": "1.3.1", 930 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", 931 | "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", 932 | "requires": { 933 | "js-tokens": "^3.0.0" 934 | } 935 | }, 936 | "meaw": { 937 | "version": "5.0.0", 938 | "resolved": "https://registry.npmjs.org/meaw/-/meaw-5.0.0.tgz", 939 | "integrity": "sha512-yaK9Pnj6JrLcQGEqDUS0WGUEiaFg9Q215isi8mzcDVOjeGr5oS863hu+/ZS49g+azKPo5Wbpk3tgkP2+YOyZZw==" 940 | }, 941 | "mimic-fn": { 942 | "version": "1.2.0", 943 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 944 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 945 | "dev": true 946 | }, 947 | "minimatch": { 948 | "version": "3.0.4", 949 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 950 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 951 | "requires": { 952 | "brace-expansion": "^1.1.7" 953 | } 954 | }, 955 | "minimist": { 956 | "version": "0.0.8", 957 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 958 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 959 | }, 960 | "mkdirp": { 961 | "version": "0.5.1", 962 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 963 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 964 | "requires": { 965 | "minimist": "0.0.8" 966 | } 967 | }, 968 | "ms": { 969 | "version": "2.0.0", 970 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 971 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 972 | }, 973 | "mute-stream": { 974 | "version": "0.0.7", 975 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 976 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", 977 | "dev": true 978 | }, 979 | "natural-compare": { 980 | "version": "1.4.0", 981 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 982 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 983 | "dev": true 984 | }, 985 | "nice-try": { 986 | "version": "1.0.5", 987 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 988 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 989 | "dev": true 990 | }, 991 | "number-is-nan": { 992 | "version": "1.0.1", 993 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 994 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 995 | }, 996 | "once": { 997 | "version": "1.4.0", 998 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 999 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1000 | "dev": true, 1001 | "requires": { 1002 | "wrappy": "1" 1003 | } 1004 | }, 1005 | "onetime": { 1006 | "version": "2.0.1", 1007 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 1008 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 1009 | "dev": true, 1010 | "requires": { 1011 | "mimic-fn": "^1.0.0" 1012 | } 1013 | }, 1014 | "optionator": { 1015 | "version": "0.8.2", 1016 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 1017 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 1018 | "dev": true, 1019 | "requires": { 1020 | "deep-is": "~0.1.3", 1021 | "fast-levenshtein": "~2.0.4", 1022 | "levn": "~0.3.0", 1023 | "prelude-ls": "~1.1.2", 1024 | "type-check": "~0.3.2", 1025 | "wordwrap": "~1.0.0" 1026 | } 1027 | }, 1028 | "os-homedir": { 1029 | "version": "1.0.2", 1030 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1031 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" 1032 | }, 1033 | "os-tmpdir": { 1034 | "version": "1.0.2", 1035 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1036 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 1037 | }, 1038 | "parent-module": { 1039 | "version": "1.0.1", 1040 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1041 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1042 | "dev": true, 1043 | "requires": { 1044 | "callsites": "^3.0.0" 1045 | } 1046 | }, 1047 | "path-is-absolute": { 1048 | "version": "1.0.1", 1049 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1050 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1051 | }, 1052 | "path-is-inside": { 1053 | "version": "1.0.2", 1054 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1055 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 1056 | "dev": true 1057 | }, 1058 | "path-key": { 1059 | "version": "2.0.1", 1060 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 1061 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 1062 | "dev": true 1063 | }, 1064 | "prelude-ls": { 1065 | "version": "1.1.2", 1066 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1067 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1068 | "dev": true 1069 | }, 1070 | "private": { 1071 | "version": "0.1.8", 1072 | "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", 1073 | "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" 1074 | }, 1075 | "progress": { 1076 | "version": "2.0.3", 1077 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1078 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1079 | "dev": true 1080 | }, 1081 | "punycode": { 1082 | "version": "2.1.1", 1083 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1084 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1085 | "dev": true 1086 | }, 1087 | "regenerator-runtime": { 1088 | "version": "0.11.1", 1089 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 1090 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 1091 | }, 1092 | "regexpp": { 1093 | "version": "2.0.1", 1094 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", 1095 | "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", 1096 | "dev": true 1097 | }, 1098 | "repeating": { 1099 | "version": "2.0.1", 1100 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 1101 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 1102 | "requires": { 1103 | "is-finite": "^1.0.0" 1104 | } 1105 | }, 1106 | "resolve-from": { 1107 | "version": "4.0.0", 1108 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1109 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1110 | "dev": true 1111 | }, 1112 | "restore-cursor": { 1113 | "version": "2.0.0", 1114 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 1115 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 1116 | "dev": true, 1117 | "requires": { 1118 | "onetime": "^2.0.0", 1119 | "signal-exit": "^3.0.2" 1120 | } 1121 | }, 1122 | "rimraf": { 1123 | "version": "2.6.3", 1124 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1125 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 1126 | "dev": true, 1127 | "requires": { 1128 | "glob": "^7.1.3" 1129 | } 1130 | }, 1131 | "run-async": { 1132 | "version": "2.3.0", 1133 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 1134 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 1135 | "dev": true, 1136 | "requires": { 1137 | "is-promise": "^2.1.0" 1138 | } 1139 | }, 1140 | "rxjs": { 1141 | "version": "6.5.1", 1142 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.1.tgz", 1143 | "integrity": "sha512-y0j31WJc83wPu31vS1VlAFW5JGrnGC+j+TtGAa1fRQphy48+fDYiDmX8tjGloToEsMkxnouOg/1IzXGKkJnZMg==", 1144 | "dev": true, 1145 | "requires": { 1146 | "tslib": "^1.9.0" 1147 | } 1148 | }, 1149 | "safe-buffer": { 1150 | "version": "5.1.2", 1151 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1152 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1153 | }, 1154 | "safer-buffer": { 1155 | "version": "2.1.2", 1156 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1157 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1158 | "dev": true 1159 | }, 1160 | "semver": { 1161 | "version": "5.7.0", 1162 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", 1163 | "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", 1164 | "dev": true 1165 | }, 1166 | "shebang-command": { 1167 | "version": "1.2.0", 1168 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1169 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1170 | "dev": true, 1171 | "requires": { 1172 | "shebang-regex": "^1.0.0" 1173 | } 1174 | }, 1175 | "shebang-regex": { 1176 | "version": "1.0.0", 1177 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1178 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1179 | "dev": true 1180 | }, 1181 | "signal-exit": { 1182 | "version": "3.0.2", 1183 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1184 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1185 | "dev": true 1186 | }, 1187 | "slash": { 1188 | "version": "1.0.0", 1189 | "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", 1190 | "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" 1191 | }, 1192 | "slice-ansi": { 1193 | "version": "2.1.0", 1194 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 1195 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", 1196 | "dev": true, 1197 | "requires": { 1198 | "ansi-styles": "^3.2.0", 1199 | "astral-regex": "^1.0.0", 1200 | "is-fullwidth-code-point": "^2.0.0" 1201 | }, 1202 | "dependencies": { 1203 | "ansi-styles": { 1204 | "version": "3.2.1", 1205 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 1206 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 1207 | "dev": true, 1208 | "requires": { 1209 | "color-convert": "^1.9.0" 1210 | } 1211 | } 1212 | } 1213 | }, 1214 | "source-map": { 1215 | "version": "0.5.7", 1216 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 1217 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 1218 | }, 1219 | "source-map-support": { 1220 | "version": "0.4.18", 1221 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", 1222 | "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", 1223 | "requires": { 1224 | "source-map": "^0.5.6" 1225 | } 1226 | }, 1227 | "sprintf-js": { 1228 | "version": "1.0.3", 1229 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1230 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1231 | "dev": true 1232 | }, 1233 | "string-width": { 1234 | "version": "2.1.1", 1235 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1236 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1237 | "dev": true, 1238 | "requires": { 1239 | "is-fullwidth-code-point": "^2.0.0", 1240 | "strip-ansi": "^4.0.0" 1241 | }, 1242 | "dependencies": { 1243 | "ansi-regex": { 1244 | "version": "3.0.0", 1245 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1246 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1247 | "dev": true 1248 | }, 1249 | "strip-ansi": { 1250 | "version": "4.0.0", 1251 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1252 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1253 | "dev": true, 1254 | "requires": { 1255 | "ansi-regex": "^3.0.0" 1256 | } 1257 | } 1258 | } 1259 | }, 1260 | "strip-ansi": { 1261 | "version": "3.0.1", 1262 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1263 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1264 | "requires": { 1265 | "ansi-regex": "^2.0.0" 1266 | } 1267 | }, 1268 | "strip-json-comments": { 1269 | "version": "2.0.1", 1270 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1271 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1272 | "dev": true 1273 | }, 1274 | "supports-color": { 1275 | "version": "2.0.0", 1276 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1277 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" 1278 | }, 1279 | "table": { 1280 | "version": "5.2.3", 1281 | "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", 1282 | "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", 1283 | "dev": true, 1284 | "requires": { 1285 | "ajv": "^6.9.1", 1286 | "lodash": "^4.17.11", 1287 | "slice-ansi": "^2.1.0", 1288 | "string-width": "^3.0.0" 1289 | }, 1290 | "dependencies": { 1291 | "ansi-regex": { 1292 | "version": "4.1.0", 1293 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1294 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1295 | "dev": true 1296 | }, 1297 | "string-width": { 1298 | "version": "3.1.0", 1299 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1300 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1301 | "dev": true, 1302 | "requires": { 1303 | "emoji-regex": "^7.0.1", 1304 | "is-fullwidth-code-point": "^2.0.0", 1305 | "strip-ansi": "^5.1.0" 1306 | } 1307 | }, 1308 | "strip-ansi": { 1309 | "version": "5.2.0", 1310 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1311 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1312 | "dev": true, 1313 | "requires": { 1314 | "ansi-regex": "^4.1.0" 1315 | } 1316 | } 1317 | } 1318 | }, 1319 | "text-table": { 1320 | "version": "0.2.0", 1321 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1322 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1323 | "dev": true 1324 | }, 1325 | "through": { 1326 | "version": "2.3.8", 1327 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1328 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1329 | "dev": true 1330 | }, 1331 | "tmp": { 1332 | "version": "0.0.33", 1333 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1334 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1335 | "dev": true, 1336 | "requires": { 1337 | "os-tmpdir": "~1.0.2" 1338 | } 1339 | }, 1340 | "to-fast-properties": { 1341 | "version": "1.0.3", 1342 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", 1343 | "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" 1344 | }, 1345 | "trim-right": { 1346 | "version": "1.0.1", 1347 | "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", 1348 | "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" 1349 | }, 1350 | "tslib": { 1351 | "version": "1.9.3", 1352 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 1353 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 1354 | "dev": true 1355 | }, 1356 | "type-check": { 1357 | "version": "0.3.2", 1358 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1359 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1360 | "dev": true, 1361 | "requires": { 1362 | "prelude-ls": "~1.1.2" 1363 | } 1364 | }, 1365 | "uri-js": { 1366 | "version": "4.2.2", 1367 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1368 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1369 | "dev": true, 1370 | "requires": { 1371 | "punycode": "^2.1.0" 1372 | } 1373 | }, 1374 | "which": { 1375 | "version": "1.3.1", 1376 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1377 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1378 | "dev": true, 1379 | "requires": { 1380 | "isexe": "^2.0.0" 1381 | } 1382 | }, 1383 | "wordwrap": { 1384 | "version": "1.0.0", 1385 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1386 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1387 | "dev": true 1388 | }, 1389 | "wrappy": { 1390 | "version": "1.0.2", 1391 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1392 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1393 | "dev": true 1394 | }, 1395 | "write": { 1396 | "version": "1.0.3", 1397 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", 1398 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", 1399 | "dev": true, 1400 | "requires": { 1401 | "mkdirp": "^0.5.1" 1402 | } 1403 | } 1404 | } 1405 | } 1406 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markdown-table-editor", 3 | "main": "./lib/markdown-table-editor.js", 4 | "version": "1.1.3", 5 | "description": "Markdown table editor/formatter", 6 | "scripts": { 7 | "lint": "eslint lib spec", 8 | "fix": "eslint lib spec --fix" 9 | }, 10 | "keywords": [ 11 | "markdown", 12 | "table" 13 | ], 14 | "activationCommands": {}, 15 | "repository": "https://github.com/susisu/atom-markdown-table-editor", 16 | "license": "MIT", 17 | "engines": { 18 | "atom": ">=1.22.0 <2.0.0" 19 | }, 20 | "devDependencies": { 21 | "eslint": "^5.16.0" 22 | }, 23 | "dependencies": { 24 | "@susisu/mte-kernel": "^2.1.1", 25 | "atom-babel6-transpiler": "^1.2.0", 26 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2" 27 | }, 28 | "atomTranspilers": [ 29 | { 30 | "glob": "{lib,spec}/*.js", 31 | "transpiler": "atom-babel6-transpiler", 32 | "options": { 33 | "babel": { 34 | "plugins": [ 35 | "transform-es2015-modules-commonjs" 36 | ], 37 | "sourceMaps": "inline", 38 | "babelrc": false 39 | } 40 | } 41 | } 42 | ], 43 | "configSchema": { 44 | "formatOnSave": { 45 | "order": 1, 46 | "title": "Format on Save", 47 | "type": "boolean", 48 | "default": false, 49 | "description": "Formats all tables on save." 50 | }, 51 | "scopes": { 52 | "order": 2, 53 | "type": "array", 54 | "items": { 55 | "type": "string" 56 | }, 57 | "default": [ 58 | "table.gfm", 59 | "table.storage.md" 60 | ], 61 | "description": "List of scopes in which the table editor is enabled." 62 | }, 63 | "leftMarginChars": { 64 | "order": 3, 65 | "title": "Left Margin Characters", 66 | "type": "string", 67 | "default": "", 68 | "description": "String of additional left margin characters." 69 | }, 70 | "formatType": { 71 | "order": 4, 72 | "type": "string", 73 | "default": "normal", 74 | "enum": [ 75 | { 76 | "value": "normal", 77 | "description": "Normal - Cells in a column have the equal width" 78 | }, 79 | { 80 | "value": "weak", 81 | "description": "Weak - Cells can have different widths" 82 | } 83 | ] 84 | }, 85 | "defaultAlignment": { 86 | "order": 5, 87 | "type": "string", 88 | "default": "left", 89 | "enum": [ 90 | { 91 | "value": "left", 92 | "description": "Left" 93 | }, 94 | { 95 | "value": "right", 96 | "description": "Right" 97 | }, 98 | { 99 | "value": "center", 100 | "description": "Center" 101 | } 102 | ] 103 | }, 104 | "headerAlignment": { 105 | "order": 6, 106 | "type": "string", 107 | "default": "follow", 108 | "enum": [ 109 | { 110 | "value": "follow", 111 | "description": "Follow column alignment" 112 | }, 113 | { 114 | "value": "left", 115 | "description": "Left" 116 | }, 117 | { 118 | "value": "right", 119 | "description": "Right" 120 | }, 121 | { 122 | "value": "center", 123 | "description": "Center" 124 | } 125 | ] 126 | }, 127 | "minDelimiterWidth": { 128 | "order": 7, 129 | "title": "Minimum Width of Delimiters", 130 | "type": "integer", 131 | "default": 3, 132 | "minimum": 1 133 | }, 134 | "ambiguousAsWide": { 135 | "order": 8, 136 | "title": "Treat East Asian Ambiguous Characters as Wide", 137 | "type": "boolean", 138 | "default": false 139 | }, 140 | "wideChars": { 141 | "order": 9, 142 | "title": "Wide Characters", 143 | "type": "string", 144 | "default": "", 145 | "description": "String of characters that should be treated as wide." 146 | }, 147 | "narrowChars": { 148 | "order": 10, 149 | "title": "Narrow Characters", 150 | "type": "string", 151 | "default": "", 152 | "description": "String of characters that should be treated as narrow." 153 | }, 154 | "normalize": { 155 | "order": 11, 156 | "title": "Unicode Normalization", 157 | "type": "boolean", 158 | "default": true, 159 | "description": "Computes cell widths based on normalized contents (NFC)." 160 | }, 161 | "smartCursor": { 162 | "order": 12, 163 | "type": "boolean", 164 | "default": true, 165 | "description": "Remembers the column where the cursor will return back on \"Next Row\" command." 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /spec/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "browser": true, 6 | "jasmine": true 7 | }, 8 | "globals": { 9 | "atom": true, 10 | "waitsForPromise": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spec/markdown-table-editor-spec.js: -------------------------------------------------------------------------------- 1 | import { Point } from "atom"; 2 | import { FormatType, DefaultAlignment, HeaderAlignment } from "@susisu/mte-kernel"; 3 | 4 | const NAMESPACE = "markdown-table-editor"; 5 | 6 | function prepareEditor(name, scope, text) { 7 | return atom.workspace.open(name) 8 | .then(editor => { 9 | const grammar = atom.grammars.grammarForScopeName(scope); 10 | expect(grammar).not.toBe(undefined); 11 | editor.setGrammar(grammar); 12 | editor.setText(text); 13 | return editor; 14 | }); 15 | } 16 | 17 | describe("markdown-table-editor", () => { 18 | beforeEach(() => { 19 | waitsForPromise(() => atom.packages.activatePackage("language-gfm")); 20 | waitsForPromise(() => atom.packages.activatePackage("markdown-table-editor")); 21 | }); 22 | 23 | describe("activation", () => { 24 | it("should be activated if the current scope is specified in the config", () => { 25 | atom.config.set(`${NAMESPACE}.scopes`, ["source.gfm", "text.md"]); 26 | const text = 27 | "\n" 28 | + "| A | B |\n" 29 | + " | --- | ----- |\n" 30 | + " | C | D | \n"; 31 | waitsForPromise(() => 32 | prepareEditor("test.md", "source.gfm", text).then(editor => { 33 | const elem = editor.getElement(); 34 | editor.setCursorBufferPosition(new Point(0, 0)); 35 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 36 | editor.setCursorBufferPosition(new Point(1, 0)); 37 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(true); 38 | editor.setCursorBufferPosition(new Point(2, 1)); 39 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(true); 40 | editor.setCursorBufferPosition(new Point(3, 2)); 41 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(true); 42 | editor.setCursorBufferPosition(new Point(4, 0)); 43 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 44 | }) 45 | ); 46 | }); 47 | 48 | it("should not be activated if the current scope is not specified in the config", () => { 49 | atom.config.set(`${NAMESPACE}.scopes`, ["text.md"]); 50 | const text = 51 | "\n" 52 | + "| A | B |\n" 53 | + " | --- | ----- |\n" 54 | + " | C | D | \n"; 55 | waitsForPromise(() => 56 | prepareEditor("test.md", "source.gfm", text).then(editor => { 57 | const elem = editor.getElement(); 58 | editor.setCursorBufferPosition(new Point(0, 0)); 59 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 60 | editor.setCursorBufferPosition(new Point(1, 0)); 61 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 62 | editor.setCursorBufferPosition(new Point(2, 1)); 63 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 64 | editor.setCursorBufferPosition(new Point(3, 2)); 65 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 66 | editor.setCursorBufferPosition(new Point(4, 0)); 67 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 68 | }) 69 | ); 70 | }); 71 | 72 | it("should not be activated if there are multiple cursors", () => { 73 | atom.config.set(`${NAMESPACE}.scopes`, ["source.gfm", "text.md"]); 74 | const text = 75 | "\n" 76 | + "| A | B |\n" 77 | + " | --- | ----- |\n" 78 | + " | C | D | \n"; 79 | waitsForPromise(() => 80 | prepareEditor("test.md", "source.gfm", text).then(editor => { 81 | const elem = editor.getElement(); 82 | const cursor = editor.getLastCursor(); 83 | cursor.setBufferPosition(new Point(1, 0)); 84 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(true); 85 | editor.addCursorAtBufferPosition(new Point(2, 1)); 86 | expect(elem.classList.contains("markdown-table-editor-active")).toBe(false); 87 | }) 88 | ); 89 | }); 90 | }); 91 | 92 | describe("commands", () => { 93 | beforeEach(() => { 94 | atom.config.set(`${NAMESPACE}.formatOnSave`, false); 95 | atom.config.set(`${NAMESPACE}.scopes`, ["source.gfm", "text.md"]); 96 | atom.config.set(`${NAMESPACE}.leftMarginChars`, ""); 97 | atom.config.set(`${NAMESPACE}.formatType`, FormatType.NORMAL); 98 | atom.config.set(`${NAMESPACE}.defaultAlignment`, DefaultAlignment.LEFT); 99 | atom.config.set(`${NAMESPACE}.headerAlignment`, HeaderAlignment.FOLLOW); 100 | atom.config.set(`${NAMESPACE}.minDelimiterWidth`, 3); 101 | atom.config.set(`${NAMESPACE}.ambiguousAsWide`, false); 102 | atom.config.set(`${NAMESPACE}.wideChars`, ""); 103 | atom.config.set(`${NAMESPACE}.narrowChars`, ""); 104 | atom.config.set(`${NAMESPACE}.normalize`, true); 105 | atom.config.set(`${NAMESPACE}.smartCursor`, false); 106 | }); 107 | 108 | describe("toggle-format-on-save", () => { 109 | it("should toggle \"Format On Save\" config", () => { 110 | waitsForPromise(() => 111 | prepareEditor("test.md", "source.gfm", "").then(editor => { 112 | editor.setCursorBufferPosition(new Point(0, 0)); 113 | expect(atom.config.get(`${NAMESPACE}.formatOnSave`)).toBe(false); 114 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:toggle-format-on-save`); 115 | expect(atom.config.get(`${NAMESPACE}.formatOnSave`)).toBe(true); 116 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:toggle-format-on-save`); 117 | expect(atom.config.get(`${NAMESPACE}.formatOnSave`)).toBe(false); 118 | }) 119 | ); 120 | }); 121 | }); 122 | 123 | describe("switch-format-type", () => { 124 | it("should switch \"Format Type\" config", () => { 125 | waitsForPromise(() => 126 | prepareEditor("test.md", "source.gfm", "").then(editor => { 127 | editor.setCursorBufferPosition(new Point(0, 0)); 128 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.NORMAL); 129 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:switch-format-type`); 130 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.WEAK); 131 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:switch-format-type`); 132 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.NORMAL); 133 | }) 134 | ); 135 | }); 136 | }); 137 | 138 | describe("set-format-type-normal", () => { 139 | it("should set \"Format Type\" to \"Normal\"", () => { 140 | waitsForPromise(() => 141 | prepareEditor("test.md", "source.gfm", "").then(editor => { 142 | editor.setCursorBufferPosition(new Point(0, 0)); 143 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.NORMAL); 144 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:set-format-type-normal`); 145 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.NORMAL); 146 | atom.config.set(`${NAMESPACE}.formatType`, FormatType.WEAK); 147 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:set-format-type-normal`); 148 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.NORMAL); 149 | }) 150 | ); 151 | }); 152 | }); 153 | 154 | describe("set-format-type-weak", () => { 155 | it("should set \"Format Type\" to \"Weak\"", () => { 156 | waitsForPromise(() => 157 | prepareEditor("test.md", "source.gfm", "").then(editor => { 158 | editor.setCursorBufferPosition(new Point(0, 0)); 159 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.NORMAL); 160 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:set-format-type-weak`); 161 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.WEAK); 162 | atom.config.set(`${NAMESPACE}.formatType`, FormatType.WEAK); 163 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:set-format-type-weak`); 164 | expect(atom.config.get(`${NAMESPACE}.formatType`)).toBe(FormatType.WEAK); 165 | }) 166 | ); 167 | }); 168 | }); 169 | 170 | describe("format", () => { 171 | it("should format the table", () => { 172 | const text = 173 | "| A | B |\n" 174 | + " | --- | ----- |\n" 175 | + " | C | D | \n"; 176 | waitsForPromise(() => 177 | prepareEditor("test.md", "source.gfm", text).then(editor => { 178 | editor.setCursorBufferPosition(new Point(0, 2)); 179 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:format`); 180 | const formatted = 181 | "| A | B |\n" 182 | + "| --- | --- |\n" 183 | + "| C | D |\n"; 184 | expect(editor.getText()).toBe(formatted); 185 | const pos = editor.getCursorBufferPosition(); 186 | expect(pos.row).toBe(0); 187 | expect(pos.column).toBe(2); 188 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 189 | }) 190 | ); 191 | }); 192 | }); 193 | 194 | describe("format-all", () => { 195 | it("should format all the tables", () => { 196 | const text = 197 | "| A | B |\n" 198 | + " | --- | ----- |\n" 199 | + " | C | D | \n" 200 | + "\n" 201 | + "| E | F |\n" 202 | + " | --- | ----- |\n" 203 | + " | G | H | \n"; 204 | waitsForPromise(() => 205 | prepareEditor("test.md", "source.gfm", text).then(editor => { 206 | editor.setCursorBufferPosition(new Point(0, 2)); 207 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:format-all`); 208 | const formatted = 209 | "| A | B |\n" 210 | + "| --- | --- |\n" 211 | + "| C | D |\n" 212 | + "\n" 213 | + "| E | F |\n" 214 | + "| --- | --- |\n" 215 | + "| G | H |\n"; 216 | expect(editor.getText()).toBe(formatted); 217 | const pos = editor.getCursorBufferPosition(); 218 | expect(pos.row).toBe(0); 219 | expect(pos.column).toBe(2); 220 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 221 | }) 222 | ); 223 | }); 224 | }); 225 | 226 | describe("escape", () => { 227 | it("should escape from the table", () => { 228 | const text = 229 | "| A | B |\n" 230 | + " | --- | ----- |\n" 231 | + " | C | D | \n"; 232 | waitsForPromise(() => 233 | prepareEditor("test.md", "source.gfm", text).then(editor => { 234 | editor.setCursorBufferPosition(new Point(0, 2)); 235 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:escape`); 236 | const formatted = 237 | "| A | B |\n" 238 | + "| --- | --- |\n" 239 | + "| C | D |\n"; 240 | expect(editor.getText()).toBe(formatted); 241 | const pos = editor.getCursorBufferPosition(); 242 | expect(pos.row).toBe(3); 243 | expect(pos.column).toBe(0); 244 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 245 | }) 246 | ); 247 | }); 248 | }); 249 | 250 | describe("align-left", () => { 251 | it("should align-left the column", () => { 252 | const text = 253 | "| A | B |\n" 254 | + " | --- | ----- |\n" 255 | + " | C | D | \n"; 256 | waitsForPromise(() => 257 | prepareEditor("test.md", "source.gfm", text).then(editor => { 258 | editor.setCursorBufferPosition(new Point(0, 2)); 259 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:align-left`); 260 | const formatted = 261 | "| A | B |\n" 262 | + "|:--- | --- |\n" 263 | + "| C | D |\n"; 264 | expect(editor.getText()).toBe(formatted); 265 | const pos = editor.getCursorBufferPosition(); 266 | expect(pos.row).toBe(0); 267 | expect(pos.column).toBe(2); 268 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 269 | }) 270 | ); 271 | }); 272 | }); 273 | 274 | describe("align-right", () => { 275 | it("should align-right the column", () => { 276 | const text = 277 | "| A | B |\n" 278 | + " | --- | ----- |\n" 279 | + " | C | D | \n"; 280 | waitsForPromise(() => 281 | prepareEditor("test.md", "source.gfm", text).then(editor => { 282 | editor.setCursorBufferPosition(new Point(0, 2)); 283 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:align-right`); 284 | const formatted = 285 | "| A | B |\n" 286 | + "| ---:| --- |\n" 287 | + "| C | D |\n"; 288 | expect(editor.getText()).toBe(formatted); 289 | const pos = editor.getCursorBufferPosition(); 290 | expect(pos.row).toBe(0); 291 | expect(pos.column).toBe(4); 292 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 293 | }) 294 | ); 295 | }); 296 | }); 297 | 298 | describe("align-center", () => { 299 | it("should align-center the column", () => { 300 | const text = 301 | "| A | B |\n" 302 | + " | --- | ----- |\n" 303 | + " | C | D | \n"; 304 | waitsForPromise(() => 305 | prepareEditor("test.md", "source.gfm", text).then(editor => { 306 | editor.setCursorBufferPosition(new Point(0, 2)); 307 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:align-center`); 308 | const formatted = 309 | "| A | B |\n" 310 | + "|:---:| --- |\n" 311 | + "| C | D |\n"; 312 | expect(editor.getText()).toBe(formatted); 313 | const pos = editor.getCursorBufferPosition(); 314 | expect(pos.row).toBe(0); 315 | expect(pos.column).toBe(3); 316 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 317 | }) 318 | ); 319 | }); 320 | }); 321 | 322 | describe("align-none", () => { 323 | it("should unset alignment of the column", () => { 324 | const text = 325 | "| A | B |\n" 326 | + " |:--- | ----- |\n" 327 | + " | C | D | \n"; 328 | waitsForPromise(() => 329 | prepareEditor("test.md", "source.gfm", text).then(editor => { 330 | editor.setCursorBufferPosition(new Point(0, 2)); 331 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:align-none`); 332 | const formatted = 333 | "| A | B |\n" 334 | + "| --- | --- |\n" 335 | + "| C | D |\n"; 336 | expect(editor.getText()).toBe(formatted); 337 | const pos = editor.getCursorBufferPosition(); 338 | expect(pos.row).toBe(0); 339 | expect(pos.column).toBe(2); 340 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 341 | }) 342 | ); 343 | }); 344 | }); 345 | 346 | describe("align-default", () => { 347 | it("should unset alignment of the column", () => { 348 | const text = 349 | "| A | B |\n" 350 | + " |:--- | ----- |\n" 351 | + " | C | D | \n"; 352 | waitsForPromise(() => 353 | prepareEditor("test.md", "source.gfm", text).then(editor => { 354 | editor.setCursorBufferPosition(new Point(0, 2)); 355 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:align-default`); 356 | const formatted = 357 | "| A | B |\n" 358 | + "| --- | --- |\n" 359 | + "| C | D |\n"; 360 | expect(editor.getText()).toBe(formatted); 361 | const pos = editor.getCursorBufferPosition(); 362 | expect(pos.row).toBe(0); 363 | expect(pos.column).toBe(2); 364 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 365 | }) 366 | ); 367 | }); 368 | }); 369 | 370 | describe("select-cell", () => { 371 | it("should select the focused cell content", () => { 372 | const text = 373 | "| A | B |\n" 374 | + " | --- | ----- |\n" 375 | + " | C | D | \n"; 376 | waitsForPromise(() => 377 | prepareEditor("test.md", "source.gfm", text).then(editor => { 378 | editor.setCursorBufferPosition(new Point(0, 2)); 379 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:select-cell`); 380 | const formatted = 381 | "| A | B |\n" 382 | + "| --- | --- |\n" 383 | + "| C | D |\n"; 384 | expect(editor.getText()).toBe(formatted); 385 | const range = editor.getSelectedBufferRange(); 386 | expect(range.start.row).toBe(0); 387 | expect(range.start.column).toBe(2); 388 | expect(range.end.row).toBe(0); 389 | expect(range.end.column).toBe(3); 390 | }) 391 | ); 392 | }); 393 | }); 394 | 395 | describe("move-left", () => { 396 | it("should move the focus left", () => { 397 | const text = 398 | "| A | B |\n" 399 | + " | --- | ----- |\n" 400 | + " | C | D | \n"; 401 | waitsForPromise(() => 402 | prepareEditor("test.md", "source.gfm", text).then(editor => { 403 | editor.setCursorBufferPosition(new Point(0, 6)); 404 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-left`); 405 | const formatted = 406 | "| A | B |\n" 407 | + "| --- | --- |\n" 408 | + "| C | D |\n"; 409 | expect(editor.getText()).toBe(formatted); 410 | const range = editor.getSelectedBufferRange(); 411 | expect(range.start.row).toBe(0); 412 | expect(range.start.column).toBe(2); 413 | expect(range.end.row).toBe(0); 414 | expect(range.end.column).toBe(3); 415 | }) 416 | ); 417 | }); 418 | }); 419 | 420 | describe("move-right", () => { 421 | it("should move the focus right", () => { 422 | const text = 423 | "| A | B |\n" 424 | + " | --- | ----- |\n" 425 | + " | C | D | \n"; 426 | waitsForPromise(() => 427 | prepareEditor("test.md", "source.gfm", text).then(editor => { 428 | editor.setCursorBufferPosition(new Point(0, 2)); 429 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-right`); 430 | const formatted = 431 | "| A | B |\n" 432 | + "| --- | --- |\n" 433 | + "| C | D |\n"; 434 | expect(editor.getText()).toBe(formatted); 435 | const range = editor.getSelectedBufferRange(); 436 | expect(range.start.row).toBe(0); 437 | expect(range.start.column).toBe(8); 438 | expect(range.end.row).toBe(0); 439 | expect(range.end.column).toBe(9); 440 | }) 441 | ); 442 | }); 443 | }); 444 | 445 | describe("move-up", () => { 446 | it("should move the focus up", () => { 447 | const text = 448 | "| A | B |\n" 449 | + " | --- | ----- |\n" 450 | + " | C | D | \n"; 451 | waitsForPromise(() => 452 | prepareEditor("test.md", "source.gfm", text).then(editor => { 453 | editor.setCursorBufferPosition(new Point(2, 4)); 454 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-up`); 455 | const formatted = 456 | "| A | B |\n" 457 | + "| --- | --- |\n" 458 | + "| C | D |\n"; 459 | expect(editor.getText()).toBe(formatted); 460 | const range = editor.getSelectedBufferRange(); 461 | expect(range.start.row).toBe(0); 462 | expect(range.start.column).toBe(2); 463 | expect(range.end.row).toBe(0); 464 | expect(range.end.column).toBe(3); 465 | }) 466 | ); 467 | }); 468 | }); 469 | 470 | describe("move-down", () => { 471 | it("should move the focus down", () => { 472 | const text = 473 | "| A | B |\n" 474 | + " | --- | ----- |\n" 475 | + " | C | D | \n"; 476 | waitsForPromise(() => 477 | prepareEditor("test.md", "source.gfm", text).then(editor => { 478 | editor.setCursorBufferPosition(new Point(0, 2)); 479 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-down`); 480 | const formatted = 481 | "| A | B |\n" 482 | + "| --- | --- |\n" 483 | + "| C | D |\n"; 484 | expect(editor.getText()).toBe(formatted); 485 | const range = editor.getSelectedBufferRange(); 486 | expect(range.start.row).toBe(2); 487 | expect(range.start.column).toBe(2); 488 | expect(range.end.row).toBe(2); 489 | expect(range.end.column).toBe(3); 490 | }) 491 | ); 492 | }); 493 | }); 494 | 495 | describe("next-cell", () => { 496 | it("should move the focus to the next cell", () => { 497 | const text = 498 | "| A | B |\n" 499 | + " | --- | ----- |\n" 500 | + " | C | D | \n"; 501 | waitsForPromise(() => 502 | prepareEditor("test.md", "source.gfm", text).then(editor => { 503 | editor.setCursorBufferPosition(new Point(0, 6)); 504 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:next-cell`); 505 | const formatted = 506 | "| A | B | \n" 507 | + "| --- | --- |\n" 508 | + "| C | D |\n"; 509 | expect(editor.getText()).toBe(formatted); 510 | const pos = editor.getCursorBufferPosition(); 511 | expect(pos.row).toBe(0); 512 | expect(pos.column).toBe(14); 513 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 514 | }) 515 | ); 516 | }); 517 | }); 518 | 519 | describe("previous-cell", () => { 520 | it("should move the focus to the previous cell", () => { 521 | const text = 522 | "| A | B |\n" 523 | + " | --- | ----- |\n" 524 | + " | C | D | \n"; 525 | waitsForPromise(() => 526 | prepareEditor("test.md", "source.gfm", text).then(editor => { 527 | editor.setCursorBufferPosition(new Point(0, 6)); 528 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:previous-cell`); 529 | const formatted = 530 | "| A | B |\n" 531 | + "| --- | --- |\n" 532 | + "| C | D |\n"; 533 | expect(editor.getText()).toBe(formatted); 534 | const range = editor.getSelectedBufferRange(); 535 | expect(range.start.row).toBe(0); 536 | expect(range.start.column).toBe(2); 537 | expect(range.end.row).toBe(0); 538 | expect(range.end.column).toBe(3); 539 | }) 540 | ); 541 | }); 542 | }); 543 | 544 | describe("next-row", () => { 545 | it("should move the focus to the next row", () => { 546 | const text = 547 | "| A | B |\n" 548 | + " | --- | ----- |\n" 549 | + " | C | D | \n"; 550 | waitsForPromise(() => 551 | prepareEditor("test.md", "source.gfm", text).then(editor => { 552 | editor.setCursorBufferPosition(new Point(2, 4)); 553 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:next-row`); 554 | const formatted = 555 | "| A | B |\n" 556 | + "| --- | --- |\n" 557 | + "| C | D |\n" 558 | + "| | |\n"; 559 | expect(editor.getText()).toBe(formatted); 560 | const pos = editor.getCursorBufferPosition(); 561 | expect(pos.row).toBe(3); 562 | expect(pos.column).toBe(2); 563 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 564 | }) 565 | ); 566 | }); 567 | }); 568 | 569 | describe("insert-row", () => { 570 | it("should insert an empty row", () => { 571 | const text = 572 | "| A | B |\n" 573 | + " | --- | ----- |\n" 574 | + " | C | D | \n"; 575 | waitsForPromise(() => 576 | prepareEditor("test.md", "source.gfm", text).then(editor => { 577 | editor.setCursorBufferPosition(new Point(2, 4)); 578 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:insert-row`); 579 | const formatted = 580 | "| A | B |\n" 581 | + "| --- | --- |\n" 582 | + "| | |\n" 583 | + "| C | D |\n"; 584 | expect(editor.getText()).toBe(formatted); 585 | const pos = editor.getCursorBufferPosition(); 586 | expect(pos.row).toBe(2); 587 | expect(pos.column).toBe(2); 588 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 589 | }) 590 | ); 591 | }); 592 | }); 593 | 594 | describe("delete-row", () => { 595 | it("should delete a row", () => { 596 | const text = 597 | "| A | B |\n" 598 | + " | --- | ----- |\n" 599 | + " | C | D | \n" 600 | + "| E | F |\n"; 601 | waitsForPromise(() => 602 | prepareEditor("test.md", "source.gfm", text).then(editor => { 603 | editor.setCursorBufferPosition(new Point(2, 4)); 604 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:delete-row`); 605 | const formatted = 606 | "| A | B |\n" 607 | + "| --- | --- |\n" 608 | + "| E | F |\n"; 609 | expect(editor.getText()).toBe(formatted); 610 | const range = editor.getSelectedBufferRange(); 611 | expect(range.start.row).toBe(2); 612 | expect(range.start.column).toBe(2); 613 | expect(range.end.row).toBe(2); 614 | expect(range.end.column).toBe(3); 615 | }) 616 | ); 617 | }); 618 | }); 619 | 620 | describe("move-row-up", () => { 621 | it("should move the focused row up", () => { 622 | const text = 623 | "| A | B |\n" 624 | + " | --- | ----- |\n" 625 | + " | C | D | \n" 626 | + "| E | F |\n"; 627 | waitsForPromise(() => 628 | prepareEditor("test.md", "source.gfm", text).then(editor => { 629 | editor.setCursorBufferPosition(new Point(3, 2)); 630 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-row-up`); 631 | const formatted = 632 | "| A | B |\n" 633 | + "| --- | --- |\n" 634 | + "| E | F |\n" 635 | + "| C | D |\n"; 636 | expect(editor.getText()).toBe(formatted); 637 | const pos = editor.getCursorBufferPosition(); 638 | expect(pos.row).toBe(2); 639 | expect(pos.column).toBe(2); 640 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 641 | }) 642 | ); 643 | }); 644 | }); 645 | 646 | describe("move-row-down", () => { 647 | it("should move the focused row down", () => { 648 | const text = 649 | "| A | B |\n" 650 | + " | --- | ----- |\n" 651 | + " | C | D | \n" 652 | + "| E | F |\n"; 653 | waitsForPromise(() => 654 | prepareEditor("test.md", "source.gfm", text).then(editor => { 655 | editor.setCursorBufferPosition(new Point(2, 4)); 656 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-row-down`); 657 | const formatted = 658 | "| A | B |\n" 659 | + "| --- | --- |\n" 660 | + "| E | F |\n" 661 | + "| C | D |\n"; 662 | expect(editor.getText()).toBe(formatted); 663 | const pos = editor.getCursorBufferPosition(); 664 | expect(pos.row).toBe(3); 665 | expect(pos.column).toBe(2); 666 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 667 | }) 668 | ); 669 | }); 670 | }); 671 | 672 | describe("insert-column", () => { 673 | it("should insert an empty column", () => { 674 | const text = 675 | "| A | B |\n" 676 | + " | --- | ----- |\n" 677 | + " | C | D | \n"; 678 | waitsForPromise(() => 679 | prepareEditor("test.md", "source.gfm", text).then(editor => { 680 | editor.setCursorBufferPosition(new Point(0, 2)); 681 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:insert-column`); 682 | const formatted = 683 | "| | A | B |\n" 684 | + "| --- | --- | --- |\n" 685 | + "| | C | D |\n"; 686 | expect(editor.getText()).toBe(formatted); 687 | const pos = editor.getCursorBufferPosition(); 688 | expect(pos.row).toBe(0); 689 | expect(pos.column).toBe(2); 690 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 691 | }) 692 | ); 693 | }); 694 | }); 695 | 696 | describe("delete-column", () => { 697 | it("should delete a column", () => { 698 | const text = 699 | "| A | B |\n" 700 | + " | --- | ----- |\n" 701 | + " | C | D | \n"; 702 | waitsForPromise(() => 703 | prepareEditor("test.md", "source.gfm", text).then(editor => { 704 | editor.setCursorBufferPosition(new Point(0, 2)); 705 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:delete-column`); 706 | const formatted = 707 | "| B |\n" 708 | + "| --- |\n" 709 | + "| D |\n"; 710 | expect(editor.getText()).toBe(formatted); 711 | const range = editor.getSelectedBufferRange(); 712 | expect(range.start.row).toBe(0); 713 | expect(range.start.column).toBe(2); 714 | expect(range.end.row).toBe(0); 715 | expect(range.end.column).toBe(3); 716 | }) 717 | ); 718 | }); 719 | }); 720 | 721 | describe("move-column-left", () => { 722 | it("should move the focused column left", () => { 723 | const text = 724 | "| A | B |\n" 725 | + " | --- | ----- |\n" 726 | + " | C | D | \n"; 727 | waitsForPromise(() => 728 | prepareEditor("test.md", "source.gfm", text).then(editor => { 729 | editor.setCursorBufferPosition(new Point(0, 6)); 730 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-column-left`); 731 | const formatted = 732 | "| B | A |\n" 733 | + "| --- | --- |\n" 734 | + "| D | C |\n"; 735 | expect(editor.getText()).toBe(formatted); 736 | const pos = editor.getCursorBufferPosition(); 737 | expect(pos.row).toBe(0); 738 | expect(pos.column).toBe(2); 739 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 740 | }) 741 | ); 742 | }); 743 | }); 744 | 745 | describe("move-column-right", () => { 746 | it("should move the focused column right", () => { 747 | const text = 748 | "| A | B |\n" 749 | + " | --- | ----- |\n" 750 | + " | C | D | \n"; 751 | waitsForPromise(() => 752 | prepareEditor("test.md", "source.gfm", text).then(editor => { 753 | editor.setCursorBufferPosition(new Point(0, 2)); 754 | atom.commands.dispatch(editor.getElement(), `${NAMESPACE}:move-column-right`); 755 | const formatted = 756 | "| B | A |\n" 757 | + "| --- | --- |\n" 758 | + "| D | C |\n"; 759 | expect(editor.getText()).toBe(formatted); 760 | const pos = editor.getCursorBufferPosition(); 761 | expect(pos.row).toBe(0); 762 | expect(pos.column).toBe(8); 763 | expect(editor.getSelectedBufferRange().isEmpty()).toBe(true); 764 | }) 765 | ); 766 | }); 767 | }); 768 | }); 769 | }); 770 | -------------------------------------------------------------------------------- /spec/text-editor-interface-spec.js: -------------------------------------------------------------------------------- 1 | import { Point, Range } from "@susisu/mte-kernel"; 2 | 3 | import TextEditorInterface from "../lib/text-editor-interface.js"; 4 | 5 | function prepareEditor(name, scope, text) { 6 | return atom.workspace.open(name) 7 | .then(editor => { 8 | const grammar = atom.grammars.grammarForScopeName(scope); 9 | expect(grammar).not.toBe(undefined); 10 | editor.setGrammar(grammar); 11 | editor.setText(text); 12 | return editor; 13 | }); 14 | } 15 | 16 | describe("TextEditorInterface", () => { 17 | beforeEach(() => { 18 | waitsForPromise(() => atom.packages.activatePackage("language-gfm")); 19 | waitsForPromise(() => atom.packages.activatePackage("language-text")); 20 | waitsForPromise(() => atom.packages.activatePackage("markdown-table-editor")); 21 | }); 22 | 23 | describe("getCursorPosition()", () => { 24 | it("should get the current cursor position as a point object", () => { 25 | const lines = [ 26 | "", 27 | "| A | B |", 28 | " | --- | ----- |", 29 | " | C | D | ", 30 | "" 31 | ]; 32 | waitsForPromise(() => 33 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 34 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 35 | editor.setCursorBufferPosition([0, 0]); 36 | { 37 | const pos = intf.getCursorPosition(); 38 | expect(pos).toBeInstanceOf(Point); 39 | expect(pos.row).toBe(0); 40 | expect(pos.column).toBe(0); 41 | } 42 | editor.setCursorBufferPosition([1, 2]); 43 | { 44 | const pos = intf.getCursorPosition(); 45 | expect(pos).toBeInstanceOf(Point); 46 | expect(pos.row).toBe(1); 47 | expect(pos.column).toBe(2); 48 | } 49 | editor.setCursorBufferPosition([4, 0]); 50 | { 51 | const pos = intf.getCursorPosition(); 52 | expect(pos).toBeInstanceOf(Point); 53 | expect(pos.row).toBe(4); 54 | expect(pos.column).toBe(0); 55 | } 56 | }) 57 | ); 58 | }); 59 | }); 60 | 61 | describe("setCursorPosition(pos)", () => { 62 | it("should set the cursor position by a point object", () => { 63 | const lines = [ 64 | "", 65 | "| A | B |", 66 | " | --- | ----- |", 67 | " | C | D | ", 68 | "" 69 | ]; 70 | waitsForPromise(() => 71 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 72 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 73 | intf.setCursorPosition(new Point(0, 0)); 74 | { 75 | const pos = editor.getCursorBufferPosition(); 76 | expect(pos.row).toBe(0); 77 | expect(pos.column).toBe(0); 78 | } 79 | intf.setCursorPosition(new Point(1, 2)); 80 | { 81 | const pos = editor.getCursorBufferPosition(); 82 | expect(pos.row).toBe(1); 83 | expect(pos.column).toBe(2); 84 | } 85 | intf.setCursorPosition(new Point(4, 0)); 86 | { 87 | const pos = editor.getCursorBufferPosition(); 88 | expect(pos.row).toBe(4); 89 | expect(pos.column).toBe(0); 90 | } 91 | }) 92 | ); 93 | }); 94 | }); 95 | 96 | describe("setSelectionRange(range)", () => { 97 | it("should set a selection by a range object", () => { 98 | const lines = [ 99 | "", 100 | "| A | B |", 101 | " | --- | ----- |", 102 | " | C | D | ", 103 | "" 104 | ]; 105 | waitsForPromise(() => 106 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 107 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 108 | intf.setSelectionRange(new Range(new Point(0, 0), new Point(1, 2))); 109 | { 110 | const range = editor.getSelectedBufferRange(); 111 | expect(range.start.row).toBe(0); 112 | expect(range.start.column).toBe(0); 113 | expect(range.end.row).toBe(1); 114 | expect(range.end.column).toBe(2); 115 | } 116 | intf.setSelectionRange(new Range(new Point(1, 2), new Point(1, 3))); 117 | { 118 | const range = editor.getSelectedBufferRange(); 119 | expect(range.start.row).toBe(1); 120 | expect(range.start.column).toBe(2); 121 | expect(range.end.row).toBe(1); 122 | expect(range.end.column).toBe(3); 123 | } 124 | intf.setSelectionRange(new Range(new Point(1, 2), new Point(4, 0))); 125 | { 126 | const range = editor.getSelectedBufferRange(); 127 | expect(range.start.row).toBe(1); 128 | expect(range.start.column).toBe(2); 129 | expect(range.end.row).toBe(4); 130 | expect(range.end.column).toBe(0); 131 | } 132 | }) 133 | ); 134 | }); 135 | }); 136 | 137 | describe("getLastRow()", () => { 138 | it("should get the last row index of the text editor", () => { 139 | const lines = [ 140 | "", 141 | "| A | B |", 142 | " | --- | ----- |", 143 | " | C | D | ", 144 | "" 145 | ]; 146 | waitsForPromise(() => 147 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 148 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 149 | expect(intf.getLastRow()).toBe(4); 150 | }) 151 | ); 152 | }); 153 | }); 154 | 155 | describe("acceptsTableEdit(row)", () => { 156 | it("should return true if the specified row is in a table", () => { 157 | { 158 | const lines = [ 159 | "", 160 | "| A | B |", 161 | "| --- | ----- |", 162 | "| C | D | ", 163 | "", 164 | "```", 165 | "| E | F |", 166 | "| --- | ----- |", 167 | "| G | H | ", 168 | "```", 169 | "" 170 | ]; 171 | waitsForPromise(() => 172 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 173 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 174 | expect(intf.acceptsTableEdit(0)).toBe(false); 175 | expect(intf.acceptsTableEdit(1)).toBe(true); 176 | expect(intf.acceptsTableEdit(2)).toBe(true); 177 | expect(intf.acceptsTableEdit(3)).toBe(true); 178 | expect(intf.acceptsTableEdit(4)).toBe(false); 179 | expect(intf.acceptsTableEdit(5)).toBe(false); 180 | expect(intf.acceptsTableEdit(6)).toBe(false); 181 | expect(intf.acceptsTableEdit(7)).toBe(false); 182 | expect(intf.acceptsTableEdit(8)).toBe(false); 183 | expect(intf.acceptsTableEdit(9)).toBe(false); 184 | expect(intf.acceptsTableEdit(10)).toBe(false); 185 | }) 186 | ); 187 | } 188 | { 189 | const lines = [ 190 | "", 191 | "| A | B |", 192 | " | --- | ----- |", 193 | " | C | D | ", 194 | "", 195 | "```", 196 | "| E | F |", 197 | " | --- | ----- |", 198 | " | G | H | ", 199 | "```", 200 | "" 201 | ]; 202 | waitsForPromise(() => 203 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 204 | const intf = new TextEditorInterface(editor, ["source.gfm"]); 205 | expect(intf.acceptsTableEdit(0)).toBe(true); 206 | expect(intf.acceptsTableEdit(1)).toBe(true); 207 | expect(intf.acceptsTableEdit(2)).toBe(true); 208 | expect(intf.acceptsTableEdit(3)).toBe(true); 209 | expect(intf.acceptsTableEdit(4)).toBe(true); 210 | expect(intf.acceptsTableEdit(5)).toBe(true); 211 | expect(intf.acceptsTableEdit(6)).toBe(true); 212 | expect(intf.acceptsTableEdit(7)).toBe(true); 213 | expect(intf.acceptsTableEdit(8)).toBe(true); 214 | expect(intf.acceptsTableEdit(9)).toBe(true); 215 | expect(intf.acceptsTableEdit(10)).toBe(true); 216 | }) 217 | ); 218 | } 219 | { 220 | const lines = [ 221 | "", 222 | "| A | B |", 223 | "| --- | ----- |", 224 | "| C | D | ", 225 | "" 226 | ]; 227 | waitsForPromise(() => 228 | prepareEditor("test.txt", "text.plain", lines.join("\n")).then(editor => { 229 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 230 | expect(intf.acceptsTableEdit(0)).toBe(false); 231 | expect(intf.acceptsTableEdit(1)).toBe(false); 232 | expect(intf.acceptsTableEdit(2)).toBe(false); 233 | expect(intf.acceptsTableEdit(3)).toBe(false); 234 | expect(intf.acceptsTableEdit(4)).toBe(false); 235 | }) 236 | ); 237 | } 238 | }); 239 | }); 240 | 241 | describe("getLine(row)", () => { 242 | it("should get a line without line ending at the specified row", () => { 243 | const lines = [ 244 | "", 245 | "| A | B |", 246 | " | --- | ----- |", 247 | " | C | D | ", 248 | "" 249 | ]; 250 | waitsForPromise(() => 251 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 252 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 253 | expect(intf.getLine(0)).toBe(""); 254 | expect(intf.getLine(1)).toBe("| A | B |"); 255 | expect(intf.getLine(2)).toBe(" | --- | ----- |"); 256 | expect(intf.getLine(3)).toBe(" | C | D | "); 257 | expect(intf.getLine(4)).toBe(""); 258 | }) 259 | ); 260 | }); 261 | }); 262 | 263 | describe("insertLine(row, line)", () => { 264 | it("should insert a new line at the specified row", () => { 265 | const lines = [ 266 | "", 267 | "| A | B |", 268 | " | --- | ----- |", 269 | " | C | D | ", 270 | "" 271 | ]; 272 | waitsForPromise(() => 273 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 274 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 275 | intf.insertLine(0, "foo"); 276 | { 277 | const text = editor.getText(); 278 | expect(text).toBe( 279 | "foo\n" 280 | + "\n" 281 | + "| A | B |\n" 282 | + " | --- | ----- |\n" 283 | + " | C | D | \n" 284 | ); 285 | } 286 | intf.insertLine(4, "| E | F |"); 287 | { 288 | const text = editor.getText(); 289 | expect(text).toBe( 290 | "foo\n" 291 | + "\n" 292 | + "| A | B |\n" 293 | + " | --- | ----- |\n" 294 | + "| E | F |\n" 295 | + " | C | D | \n" 296 | ); 297 | } 298 | intf.insertLine(7, "bar"); 299 | { 300 | const text = editor.getText(); 301 | expect(text).toBe( 302 | "foo\n" 303 | + "\n" 304 | + "| A | B |\n" 305 | + " | --- | ----- |\n" 306 | + "| E | F |\n" 307 | + " | C | D | \n" 308 | + "\n" 309 | + "bar" 310 | ); 311 | } 312 | }) 313 | ); 314 | }); 315 | }); 316 | 317 | describe("deleteLine(row)", () => { 318 | it("should delete a line at the specified row", () => { 319 | const lines = [ 320 | "foo", 321 | "", 322 | "| A | B |", 323 | " | --- | ----- |", 324 | " | C | D | ", 325 | "| E | F |", 326 | "| G | H |", 327 | "" 328 | ]; 329 | waitsForPromise(() => 330 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 331 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 332 | intf.deleteLine(0); 333 | { 334 | const text = editor.getText(); 335 | expect(text).toBe( 336 | "\n" 337 | + "| A | B |\n" 338 | + " | --- | ----- |\n" 339 | + " | C | D | \n" 340 | + "| E | F |\n" 341 | + "| G | H |\n" 342 | ); 343 | } 344 | intf.deleteLine(3); 345 | { 346 | const text = editor.getText(); 347 | expect(text).toBe( 348 | "\n" 349 | + "| A | B |\n" 350 | + " | --- | ----- |\n" 351 | + "| E | F |\n" 352 | + "| G | H |\n" 353 | ); 354 | } 355 | intf.deleteLine(5); 356 | { 357 | const text = editor.getText(); 358 | expect(text).toBe( 359 | "\n" 360 | + "| A | B |\n" 361 | + " | --- | ----- |\n" 362 | + "| E | F |\n" 363 | + "| G | H |" 364 | ); 365 | } 366 | }) 367 | ); 368 | }); 369 | }); 370 | 371 | describe("replaceLines(startRow, endRow, lines)", () => { 372 | it("should replace lines in the specified row range", () => { 373 | const lines = [ 374 | "", 375 | "| A | B |", 376 | " | --- | ----- |", 377 | " | C | D | ", 378 | "" 379 | ]; 380 | waitsForPromise(() => 381 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 382 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 383 | { 384 | const newLines = [ 385 | "| A | B |", 386 | "| --- | --- |", 387 | "| C | D |", 388 | "| E | F |" 389 | ]; 390 | intf.replaceLines(1, 4, newLines); 391 | const text = editor.getText(); 392 | expect(text).toBe( 393 | "\n" 394 | + "| A | B |\n" 395 | + "| --- | --- |\n" 396 | + "| C | D |\n" 397 | + "| E | F |\n" 398 | ); 399 | } 400 | { 401 | const newLines = [ 402 | "| G | H |", 403 | "| --- | --- |", 404 | "| I | J |" 405 | ]; 406 | intf.replaceLines(1, 6, newLines); 407 | const text = editor.getText(); 408 | expect(text).toBe( 409 | "\n" 410 | + "| G | H |\n" 411 | + "| --- | --- |\n" 412 | + "| I | J |" 413 | ); 414 | } 415 | }) 416 | ); 417 | }); 418 | }); 419 | 420 | describe("transact(func)", () => { 421 | it("should batch operations as a single step", () => { 422 | const lines = [ 423 | "", 424 | "| A | B |", 425 | " | --- | ----- |", 426 | " | C | D | ", 427 | "" 428 | ]; 429 | waitsForPromise(() => 430 | prepareEditor("test.md", "source.gfm", lines.join("\n")).then(editor => { 431 | const intf = new TextEditorInterface(editor, ["table.gfm"]); 432 | intf.transact(() => { 433 | intf.deleteLine(3); 434 | intf.insertLine(3, "| E | F |"); 435 | }); 436 | { 437 | const text = editor.getText(); 438 | expect(text).toBe( 439 | "\n" 440 | + "| A | B |\n" 441 | + " | --- | ----- |\n" 442 | + "| E | F |\n" 443 | ); 444 | } 445 | editor.undo(); 446 | { 447 | const text = editor.getText(); 448 | expect(text).toBe( 449 | "\n" 450 | + "| A | B |\n" 451 | + " | --- | ----- |\n" 452 | + " | C | D | \n" 453 | ); 454 | } 455 | }) 456 | ); 457 | }); 458 | }); 459 | }); 460 | --------------------------------------------------------------------------------