├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitconfig
├── .github
└── workflows
│ └── node.js.yml
├── .gitignore
├── .languagebabel
├── .tern-project
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── bin
├── commands
│ ├── acronym.js
│ ├── completion.js
│ ├── configuration.js
│ ├── configuration
│ │ ├── get.js
│ │ ├── init.js
│ │ └── set.js
│ ├── datamuse.js
│ ├── datamuse
│ │ ├── get.js
│ │ └── info.js
│ ├── list.js
│ ├── onelook.js
│ ├── random.js
│ ├── rhymebrain.js
│ ├── rhymebrain
│ │ ├── combine.js
│ │ ├── info.js
│ │ └── rhyme.js
│ ├── urban.js
│ ├── wordmap.js
│ ├── wordnik.js
│ └── wordnik
│ │ ├── define.js
│ │ ├── example.js
│ │ ├── hyphen.js
│ │ ├── origin.js
│ │ ├── phrase.js
│ │ ├── pronounce.js
│ │ └── relate.js
├── leximaven.js
├── themes.js
└── tools.js
├── default.config.noon
├── package-lock.json
├── package.json
├── pnpm-lock.yaml
├── src
├── commands
│ ├── acronym.js
│ ├── completion.js
│ ├── configuration.js
│ ├── configuration
│ │ ├── get.js
│ │ ├── init.js
│ │ └── set.js
│ ├── datamuse.js
│ ├── datamuse
│ │ ├── get.js
│ │ └── info.js
│ ├── list.js
│ ├── onelook.js
│ ├── random.js
│ ├── rhymebrain.js
│ ├── rhymebrain
│ │ ├── combine.js
│ │ ├── info.js
│ │ └── rhyme.js
│ ├── urban.js
│ ├── wordmap.js
│ ├── wordnik.js
│ └── wordnik
│ │ ├── define.js
│ │ ├── example.js
│ │ ├── hyphen.js
│ │ ├── origin.js
│ │ ├── phrase.js
│ │ ├── pronounce.js
│ │ └── relate.js
├── leximaven.js
├── themes.js
└── tools.js
├── test.sh
└── themes
├── colonel.noon
├── markup.noon
└── square.noon
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"],
3 | "compact": true,
4 | "env": {
5 | "dev": {
6 | "plugins": ["lodash"]
7 | },
8 | "test": {
9 | "plugins": ["lodash"]
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 |
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [*.noon]
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*{.,-}min.js
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | ecmaFeatures:
2 | modules: true
3 | jsx: true
4 |
5 | env:
6 | amd: true
7 | browser: true
8 | es6: true
9 | jquery: true
10 | node: true
11 |
12 | # http://eslint.org/docs/rules/
13 | rules:
14 | # Possible Errors
15 | comma-dangle: [2, never]
16 | no-cond-assign: 2
17 | no-console: 0
18 | no-constant-condition: 2
19 | no-control-regex: 2
20 | no-debugger: 2
21 | no-dupe-args: 2
22 | no-dupe-keys: 2
23 | no-duplicate-case: 2
24 | no-empty: 2
25 | no-empty-character-class: 2
26 | no-ex-assign: 2
27 | no-extra-boolean-cast: 2
28 | no-extra-parens: 0
29 | no-extra-semi: 2
30 | no-func-assign: 2
31 | no-inner-declarations: [2, functions]
32 | no-invalid-regexp: 2
33 | no-irregular-whitespace: 2
34 | no-negated-in-lhs: 2
35 | no-obj-calls: 2
36 | no-regex-spaces: 2
37 | no-sparse-arrays: 2
38 | no-unexpected-multiline: 2
39 | no-unreachable: 2
40 | use-isnan: 2
41 | valid-jsdoc: 0
42 | valid-typeof: 2
43 |
44 | # Best Practices
45 | accessor-pairs: 2
46 | block-scoped-var: 0
47 | complexity: [2, 6]
48 | consistent-return: 0
49 | curly: 0
50 | default-case: 0
51 | dot-location: 0
52 | dot-notation: 0
53 | eqeqeq: 2
54 | guard-for-in: 2
55 | no-alert: 2
56 | no-caller: 2
57 | no-case-declarations: 2
58 | no-div-regex: 2
59 | no-else-return: 0
60 | no-empty-label: 2
61 | no-empty-pattern: 2
62 | no-eq-null: 2
63 | no-eval: 2
64 | no-extend-native: 2
65 | no-extra-bind: 2
66 | no-fallthrough: 2
67 | no-floating-decimal: 0
68 | no-implicit-coercion: 0
69 | no-implied-eval: 2
70 | no-invalid-this: 0
71 | no-iterator: 2
72 | no-labels: 0
73 | no-lone-blocks: 2
74 | no-loop-func: 2
75 | no-magic-number: 0
76 | no-multi-spaces: 0
77 | no-multi-str: 0
78 | no-native-reassign: 2
79 | no-new-func: 2
80 | no-new-wrappers: 2
81 | no-new: 2
82 | no-octal-escape: 2
83 | no-octal: 2
84 | no-proto: 2
85 | no-redeclare: 2
86 | no-return-assign: 2
87 | no-script-url: 2
88 | no-self-compare: 2
89 | no-sequences: 0
90 | no-throw-literal: 0
91 | no-unused-expressions: 2
92 | no-useless-call: 2
93 | no-useless-concat: 2
94 | no-void: 2
95 | no-warning-comments: 0
96 | no-with: 2
97 | radix: 2
98 | vars-on-top: 0
99 | wrap-iife: 2
100 | yoda: 0
101 |
102 | # Strict
103 | strict: 0
104 |
105 | # Variables
106 | init-declarations: 0
107 | no-catch-shadow: 2
108 | no-delete-var: 2
109 | no-label-var: 2
110 | no-shadow-restricted-names: 2
111 | no-shadow: 0
112 | no-undef-init: 2
113 | no-undef: 0
114 | no-undefined: 0
115 | no-unused-vars: 0
116 | no-use-before-define: 0
117 |
118 | # Node.js and CommonJS
119 | callback-return: 2
120 | global-require: 2
121 | handle-callback-err: 2
122 | no-mixed-requires: 0
123 | no-new-require: 0
124 | no-path-concat: 2
125 | no-process-exit: 2
126 | no-restricted-modules: 0
127 | no-sync: 0
128 |
129 | # Stylistic Issues
130 | array-bracket-spacing: 0
131 | block-spacing: 0
132 | brace-style: 0
133 | camelcase: 0
134 | comma-spacing: 0
135 | comma-style: 0
136 | computed-property-spacing: 0
137 | consistent-this: 0
138 | eol-last: 0
139 | func-names: 0
140 | func-style: 0
141 | id-length: 0
142 | id-match: 0
143 | indent: 0
144 | jsx-quotes: 0
145 | key-spacing: 0
146 | linebreak-style: 0
147 | lines-around-comment: 0
148 | max-depth: 0
149 | max-len: 0
150 | max-nested-callbacks: 0
151 | max-params: 0
152 | max-statements: [2, 30]
153 | new-cap: 0
154 | new-parens: 0
155 | newline-after-var: 0
156 | no-array-constructor: 0
157 | no-bitwise: 0
158 | no-continue: 0
159 | no-inline-comments: 0
160 | no-lonely-if: 0
161 | no-mixed-spaces-and-tabs: 0
162 | no-multiple-empty-lines: 0
163 | no-negated-condition: 0
164 | no-nested-ternary: 0
165 | no-new-object: 0
166 | no-plusplus: 0
167 | no-restricted-syntax: 0
168 | no-spaced-func: 0
169 | no-ternary: 0
170 | no-trailing-spaces: 0
171 | no-underscore-dangle: 0
172 | no-unneeded-ternary: 0
173 | object-curly-spacing: 0
174 | one-var: 0
175 | operator-assignment: 0
176 | operator-linebreak: 0
177 | padded-blocks: 0
178 | quote-props: 0
179 | quotes: 0
180 | require-jsdoc: 0
181 | semi-spacing: 0
182 | semi: 0
183 | sort-vars: 0
184 | space-after-keywords: 0
185 | space-before-blocks: 0
186 | space-before-function-paren: 0
187 | space-before-keywords: 0
188 | space-in-parens: 0
189 | space-infix-ops: 0
190 | space-return-throw-case: 0
191 | space-unary-ops: 0
192 | spaced-comment: 0
193 | wrap-regex: 0
194 |
195 | # ECMAScript 6
196 | arrow-body-style: 0
197 | arrow-parens: 0
198 | arrow-spacing: 0
199 | constructor-super: 0
200 | generator-star-spacing: 0
201 | no-arrow-condition: 0
202 | no-class-assign: 0
203 | no-const-assign: 0
204 | no-dupe-class-members: 0
205 | no-this-before-super: 0
206 | no-var: 0
207 | object-shorthand: 0
208 | prefer-arrow-callback: 0
209 | prefer-const: 0
210 | prefer-reflect: 0
211 | prefer-spread: 0
212 | prefer-template: 0
213 | require-yield: 0
214 |
--------------------------------------------------------------------------------
/.gitconfig:
--------------------------------------------------------------------------------
1 | # drawnepicenter
2 | Host drawnepicenter.github.com
3 | HostName github.com
4 | PreferredAuthentications publickey
5 | IdentityFile ~/.ssh/de_rsa
6 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version: [18.x]
20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21 |
22 | steps:
23 | - uses: actions/checkout@v3
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v3
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 | cache: 'npm'
29 | - run: npm ci
30 | - run: npm run build --if-present
31 | - run: npm test
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 | node_modules
23 | .gitconfig
24 |
25 | # Project specific
26 | .sync
27 | docs
28 | scripts
29 | staging
30 | wiki
31 | TODO.md
32 | jsdoc.conf.json
33 | json
34 | .nvmrc
35 | .syncthing*
36 | lcov.info
37 | .babelrc
38 | .eslintignore
39 | .eslintrc
40 | .languagebabel
41 | .tern-project
42 | *.code-workspace
43 | yarn.lock
44 | ptags.fish
45 |
--------------------------------------------------------------------------------
/.languagebabel:
--------------------------------------------------------------------------------
1 | {
2 | "babelMapsPath": "bin",
3 | "babelMapsAddUrl": true,
4 | "babelSourcePath": "src",
5 | "babelTranspilePath": "bin",
6 | "createMap": false,
7 | "createTargetDirectories": true,
8 | "createTranspiledCode": true,
9 | "disableWhenNoBabelrcFileInPath": true,
10 | "suppressSourcePathMessages": true,
11 | "suppressTranspileOnSaveMessages": true,
12 | "transpileOnSave": false
13 | }
14 |
--------------------------------------------------------------------------------
/.tern-project:
--------------------------------------------------------------------------------
1 | {
2 | "ecmaVersion": 6,
3 | "libs": ["chai"],
4 | "loadEagerly": [
5 | "src/**/*.js",
6 | "test/*.es6"
7 | ],
8 | "dontLoad": ["node_modules/**/*"],
9 | "plugins": {
10 | "doc_comment": {
11 | "fullDocs": true
12 | },
13 | "complete_strings": {
14 | "maxLength": 25
15 | },
16 | "modules": {},
17 | "es_modules": {},
18 | "eslint": {
19 | "config": {
20 | "env": {
21 | "browser": false
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '14'
4 | before_script:
5 | - npm i -g
6 | - leximaven config init
7 | script: ./test.sh
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 |
6 | # [4.0.0](https://github.com/drawnepicenter/leximaven/compare/v3.0.0...v4.0.0) (2019-01-04)
7 |
8 |
9 | ### Features
10 |
11 | * **project:** resurrect ([793e1e4](https://github.com/drawnepicenter/leximaven/commit/793e1e4)), closes [#25](https://github.com/drawnepicenter/leximaven/issues/25) [#26](https://github.com/drawnepicenter/leximaven/issues/26)
12 |
13 |
14 | ### BREAKING CHANGES
15 |
16 | * **project:** Right now anagrams are disabled. I'm effectively removing this feature for now
17 |
18 |
19 |
20 |
21 | # [3.0.0](https://github.com/drawnepicenter/leximaven/compare/v2.3.4...v3.0.0) (2017-08-30)
22 |
23 |
24 | ### Features
25 |
26 | * **project:** BREAKING_CHANGES:remove tests ([0113744](https://github.com/drawnepicenter/leximaven/commit/0113744))
27 |
28 |
29 | ### BREAKING CHANGES
30 |
31 | * **project:** remove tests
32 |
33 |
34 |
35 |
36 | ## [2.3.4](https://github.com/drawnepicenter/leximaven/compare/v2.3.3...v2.3.4) (2017-02-05)
37 |
38 |
39 | ### Bug Fixes
40 |
41 | * **wordmap:** require 'fs' ([e21d630](https://github.com/drawnepicenter/leximaven/commit/e21d630))
42 |
43 |
44 |
45 |
46 | ## [2.3.3](https://github.com/drawnepicenter/leximaven/compare/v2.3.2...v2.3.3) (2017-01-29)
47 |
48 |
49 | ### Bug Fixes
50 |
51 | * **configuration:** missing command aliases ([d368b8d](https://github.com/drawnepicenter/leximaven/commit/d368b8d))
52 |
53 |
54 |
55 |
56 | ## [2.3.2](https://github.com/drawnepicenter/leximaven/compare/v2.3.1...v2.3.2) (2017-01-29)
57 |
58 |
59 | ### Bug Fixes
60 |
61 | * **wordmap:** mapping doesn't work in other directories as a package ([17b01e1](https://github.com/drawnepicenter/leximaven/commit/17b01e1))
62 |
63 |
64 |
65 |
66 | ## [2.3.1](https://github.com/drawnepicenter/leximaven/compare/v2.3.0...v2.3.1) (2017-01-25)
67 |
68 |
69 | ### Bug Fixes
70 |
71 | * **project:** config init error ([8b0bfa1](https://github.com/drawnepicenter/leximaven/commit/8b0bfa1))
72 | * **themes:** control fallback msg with verbose ([9e3de72](https://github.com/drawnepicenter/leximaven/commit/9e3de72)), closes [#16](https://github.com/drawnepicenter/leximaven/issues/16)
73 |
74 |
75 |
76 |
77 | # [2.3.0](https://github.com/drawnepicenter/leximaven/compare/v2.2.0...v2.3.0) (2017-01-23)
78 |
79 |
80 | ### Features
81 |
82 | * **project:** add random word command ([4d782be](https://github.com/drawnepicenter/leximaven/commit/4d782be)), closes [#14](https://github.com/drawnepicenter/leximaven/issues/14)
83 |
84 |
85 |
86 |
87 | # [2.2.0](https://github.com/drawnepicenter/leximaven/compare/v2.1.0...v2.2.0) (2017-01-21)
88 |
89 |
90 | ### Features
91 |
92 | * **project:** add command aliases ([4597a8c](https://github.com/drawnepicenter/leximaven/commit/4597a8c))
93 |
94 |
95 |
96 |
97 | # [2.1.0](https://github.com/drawnepicenter/leximaven/compare/v2.0.0...v2.1.0) (2017-01-09)
98 |
99 |
100 | ### Bug Fixes
101 |
102 | * **tools:** move fs-extra to runtime deps ([95067ab](https://github.com/drawnepicenter/leximaven/commit/95067ab))
103 |
104 |
105 | ### Features
106 |
107 | * **tools:** add functions from iloa ([35ceabd](https://github.com/drawnepicenter/leximaven/commit/35ceabd))
108 |
109 |
110 |
111 |
112 | # [2.0.0](https://github.com/drawnepicenter/leximaven/compare/v1.2.0...v2.0.0) (2016-09-15)
113 |
114 |
115 | ### Bug Fixes
116 |
117 | * **project:** proper HTTP error msg ([9eef640](https://github.com/drawnepicenter/leximaven/commit/9eef640))
118 |
119 |
120 | ### Features
121 |
122 | * **project:** rename build dir to bin, simplify gulpfile, simplify command file and dir names ([208250e](https://github.com/drawnepicenter/leximaven/commit/208250e))
123 |
124 |
125 | ### BREAKING CHANGES
126 |
127 | * project: See items listed in #12
128 |
129 |
130 |
131 |
132 | # [1.2.0](https://github.com/drawnepicenter/leximaven/compare/v1.1.0...v1.2.0) (2016-08-26)
133 |
134 |
135 | ### Bug Fixes
136 |
137 | * **wordnik:** remove url from outfile ([2dac4dc](https://github.com/drawnepicenter/leximaven/commit/2dac4dc)), closes [#8](https://github.com/drawnepicenter/leximaven/issues/8)
138 |
139 |
140 | ### Features
141 |
142 | * **wordnik:** check for API key ([bbf9dab](https://github.com/drawnepicenter/leximaven/commit/bbf9dab))
143 |
144 |
145 |
146 |
147 | # [1.1.0](https://github.com/drawnepicenter/leximaven/compare/v1.0.2...v1.1.0) (2016-08-26)
148 |
149 |
150 | ### Bug Fixes
151 |
152 | * **rbrain:** Add timestamp expired msg to usage info ([422df3c](https://github.com/drawnepicenter/leximaven/commit/422df3c))
153 |
154 |
155 | ### Features
156 |
157 | * **dmuse:** cached response won't decrement usage ([3973511](https://github.com/drawnepicenter/leximaven/commit/3973511))
158 | * **onelook:** cached response won't decrement usage ([01bd9f0](https://github.com/drawnepicenter/leximaven/commit/01bd9f0))
159 | * **rbrain:** cached response won't decrement usage ([613be73](https://github.com/drawnepicenter/leximaven/commit/613be73))
160 | * **wordnik:** cached response won't decrement usage ([9783ea8](https://github.com/drawnepicenter/leximaven/commit/9783ea8))
161 |
162 |
163 |
164 |
165 | ## [1.0.2](https://github.com/drawnepicenter/leximaven/compare/v1.0.1...v1.0.2) (2016-08-19)
166 |
167 |
168 | ### Bug Fixes
169 |
170 | * **CI:** remove strip-ansi require ([48efa39](https://github.com/drawnepicenter/leximaven/commit/48efa39))
171 | * **cli-tests:** stringify error ([9c9932d](https://github.com/drawnepicenter/leximaven/commit/9c9932d))
172 | * **config-init:** no more JSON stringify creating problems with babel-polyfill ([8a9dca8](https://github.com/drawnepicenter/leximaven/commit/8a9dca8)), closes [#6](https://github.com/drawnepicenter/leximaven/issues/6)
173 |
174 |
175 |
176 |
177 | ## [1.0.1](https://github.com/drawnepicenter/leximaven/compare/v1.0.0...v1.0.1) (2016-08-17)
178 |
179 |
180 |
181 |
182 | # [1.0.0](https://github.com/drawnepicenter/leximaven/compare/v0.1.4...v1.0.0) (2016-08-17)
183 |
184 |
185 | ### Bug Fixes
186 |
187 | * **CI:** don't test on 4.x or iojs ([7380d8c](https://github.com/drawnepicenter/leximaven/commit/7380d8c))
188 | * **CI:** theme dir gets set correctly ([194e123](https://github.com/drawnepicenter/leximaven/commit/194e123))
189 | * **onelook:** extract strings from arrays ([9e504d1](https://github.com/drawnepicenter/leximaven/commit/9e504d1)), closes [#4](https://github.com/drawnepicenter/leximaven/issues/4)
190 | * **themes:** undefined/connector printing with label ([af53971](https://github.com/drawnepicenter/leximaven/commit/af53971))
191 | * **urban:** addtl args don't include 'urban' ([ac11277](https://github.com/drawnepicenter/leximaven/commit/ac11277))
192 | * **urban-hyphen:** incorrect labelling ([9388081](https://github.com/drawnepicenter/leximaven/commit/9388081))
193 |
194 |
195 | ### Features
196 |
197 | * **tools:** arrToStr function ([1f5ea44](https://github.com/drawnepicenter/leximaven/commit/1f5ea44))
198 |
199 |
200 | ### BREAKING CHANGES
201 |
202 | * CI: All changes listed in #5
203 |
204 |
205 |
206 |
207 | ## [0.1.4](https://github.com/drawnepicenter/leximaven/compare/v0.1.3...v0.1.4) (2016-08-03)
208 |
209 |
210 | ### Bug Fixes
211 |
212 | * **project:** use repo dir or pkg dir ([f13cdd1](https://github.com/drawnepicenter/leximaven/commit/f13cdd1))
213 |
214 |
215 |
216 |
217 | ## [0.1.3](https://github.com/drawnepicenter/leximaven/compare/v0.1.2...v0.1.3) (2016-08-02)
218 |
219 |
220 | ### Bug Fixes
221 |
222 | * **project:** package directory access ([2d60a1c](https://github.com/drawnepicenter/leximaven/commit/2d60a1c))
223 |
224 |
225 |
226 |
227 | ## [0.1.2](https://github.com/drawnepicenter/leximaven/compare/v0.1.1...v0.1.2) (2016-08-02)
228 |
229 |
230 | ### Bug Fixes
231 |
232 | * **project:** add PKGDIR ([fb504d9](https://github.com/drawnepicenter/leximaven/commit/fb504d9))
233 |
234 |
235 |
236 |
237 | ## [0.1.1](https://github.com/drawnepicenter/leximaven/compare/v0.1.0...v0.1.1) (2016-08-01)
238 |
239 |
240 | ### Bug Fixes
241 |
242 | * make glob a runtime dep ([c3b5afb](https://github.com/drawnepicenter/leximaven/commit/c3b5afb))
243 |
244 |
245 |
246 |
247 | # 0.1.0 (2016-08-01)
248 |
249 |
250 | ### Bug Fixes
251 |
252 | * **combine:** fix tofile ([df453fa](https://github.com/drawnepicenter/leximaven/commit/df453fa))
253 | * **config:** init timestamps and verbose output ([85f86ec](https://github.com/drawnepicenter/leximaven/commit/85f86ec))
254 | * **config-init:** Save remain for rate-limiting ([290986a](https://github.com/drawnepicenter/leximaven/commit/290986a))
255 | * **config-init:** Saves remaing requests for rate-limiting ([7714a4f](https://github.com/drawnepicenter/leximaven/commit/7714a4f))
256 | * **datamuse:** fix arg parsing ([5b153f3](https://github.com/drawnepicenter/leximaven/commit/5b153f3))
257 | * **list-themes:** filepath str replace ([5180a76](https://github.com/drawnepicenter/leximaven/commit/5180a76))
258 | * **origin:** fix output ([b656aaf](https://github.com/drawnepicenter/leximaven/commit/b656aaf))
259 | * **origin:** fix tofile ([5b93352](https://github.com/drawnepicenter/leximaven/commit/5b93352))
260 | * **project:** fix rate-limiting ([c13907a](https://github.com/drawnepicenter/leximaven/commit/c13907a))
261 | * **project:** fix tests ([c9517e5](https://github.com/drawnepicenter/leximaven/commit/c9517e5))
262 | * **project:** init before CI ([41e66f8](https://github.com/drawnepicenter/leximaven/commit/41e66f8))
263 | * **project:** yargs install ([4402f7e](https://github.com/drawnepicenter/leximaven/commit/4402f7e))
264 | * **rbrain-info:** remove maxResults ([d9736d4](https://github.com/drawnepicenter/leximaven/commit/d9736d4))
265 | * **rbrain-rhyme:** parsing values ([2b342b0](https://github.com/drawnepicenter/leximaven/commit/2b342b0))
266 | * **rhymebrain:** rate limiting output ([2a13efe](https://github.com/drawnepicenter/leximaven/commit/2a13efe))
267 | * **rhymebrain:** rate-limiting and result output ([5b98c47](https://github.com/drawnepicenter/leximaven/commit/5b98c47))
268 | * **rhymebrain:** remove debug console.log ([c82c8a0](https://github.com/drawnepicenter/leximaven/commit/c82c8a0))
269 | * **urban:** fix args ([59877f8](https://github.com/drawnepicenter/leximaven/commit/59877f8))
270 | * **wordmap:** change bin to build ([6b0ed9c](https://github.com/drawnepicenter/leximaven/commit/6b0ed9c))
271 |
272 |
273 | ### Features
274 |
275 | * **dmuse:** add metrics, pull into subcmds ([e0b2483](https://github.com/drawnepicenter/leximaven/commit/e0b2483))
276 | * **project:** datamuse subcmds and add rate-limiting ([94cb7f6](https://github.com/drawnepicenter/leximaven/commit/94cb7f6))
277 | * **project:** url in serialized output file ([2fc81d8](https://github.com/drawnepicenter/leximaven/commit/2fc81d8))
278 | * add api usage option ([67ff191](https://github.com/drawnepicenter/leximaven/commit/67ff191))
279 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | As of right now, I am the only one contributing to this project. I welcome you to open issues and submit pull requests so that leximaven can be even better.
4 |
5 | ### Build process & Development Cycle
6 |
7 | - Build is managed with npm scripts. [redrun](https://github.com/coderaiser/redrun) is my task runner. Here are the tasks:
8 |
9 | - **bin** - transpiles src into bin
10 | - **bump** - after release task, pushes version to repo and publishes npm package
11 | - **lint** - fixes stylistic issues in src folder
12 | - **release** - uses standard-version to update the CHANGELOG and modify the version in package.json
13 | - **watch** - watches src directory for changes and automatically compiles to bin folder
14 |
15 | ### Changelog & Versioning
16 |
17 | - leximaven uses the [conventional-changelog](https://github.com/conventional-changelog/conventional-changelog-angular/blob/master/convention.md) format. [commitizen](http://commitizen.github.io/cz-cli/) automates this formatting.
18 | - There is no development branch on top of master, so the workflow is clean and simple. [git town](http://www.git-town.com/) helps automate this workflow.
19 | - [standard-version](https://github.com/conventional-changelog/standard-version) automates [semantic versioning](http://semver.org/spec/v2.0.0.html) and changelog generation.
20 | - See the [CHANGELOG](https://github.com/drawnepicenter/leximaven/blob/master/CHANGELOG.md) for progress.
21 |
22 | ### Coding Style & Linting
23 |
24 | This project adheres to [standard](https://github.com/feross/standard) formatting rules.
25 |
26 | ### Testing
27 |
28 | I was using Mocha, Chai, and Sinon for testing. At the moment there are no tests.
29 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | **Copyright (c) 2017-2019 Andrew Prentice**
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | **THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.**
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # leximaven
2 |
3 | [](https://travis-ci.org/scalarwaves/leximaven) [](https://badge.fury.io/js/leximaven) [](http://standardjs.com/)
4 |
5 | ## Introduction
6 |
7 | leximaven is a powerful tool for searching word-related APIs from the command line. It can fetch acronyms, bi-gram phrases, definitions, etymologies, example uses, hyphenation, offensive word flags, portmanteaus, pronunciations (Arpabet & IPA), related words, rhymes, slang, syllable stress and count, and more. See the [wiki](https://github.com/drawnepicenter/leximaven/wiki) for more info.
8 |
9 | ## Platform
10 |
11 | Looking for testers on other platforms. Developed and tested on Linux. Works on Windows, see [Windows](#windows-installation) below.
12 |
13 | Supported Node.js versions:
14 |
15 | - Typescript
16 | - 12.x
17 | - 11.x
18 | - 10.x
19 | - 8.x
20 |
21 | ## Install
22 |
23 | ### Linux installation
24 |
25 | To initialize the config file and load themes, your NODE_PATH environment variable must point to the **node_modules** directory of the Node.js installation. You can set this path automatically like this:
26 |
27 | export NP=$(which node)
28 | export BP=${NP%bin/node} #this replaces the string '/bin/node'
29 | export LP="${BP}lib/node_modules"
30 | export NODE_PATH="$LP"
31 |
32 | Provided these lines are towards the end of the shell initialization file (at least after any NVM stuff) this should work for a system installation of Node.js and [nvm](https://github.com/creationix/nvm).
33 |
34 | - Put your [Wordnik API key](http://developer.wordnik.com/) into an environment variable **WORDNIK**
35 |
36 | Add all of this to .bashrc, .zshrc, etc. then:
37 |
38 | npm install -g leximaven
39 | leximaven config init
40 |
41 | ### Windows installation
42 |
43 | I highly recommend using [nodist](https://github.com/marcelklehr/nodist) to install Node.js on Windows. It automatically sets %NODE_PATH% for you, though you may have to edit it to make sure it doesn't contain itself (i.e. C:\...\...\node_modules;%NODE_PATH%). If you install Node.js manually, `npm install --global leximaven` will install the package in C:\Users\username\AppData\Roaming\npm\node_modules. And if you just do `npm install leximaven` then it will install the package to a subfolder of the Node.js installation, but that won't be the NODE_PATH folder unless you manually set it. Either way, you're going to have to mess around with Windows environment variables to get it to work. And don't forget to put your [Wordnik API key](http://developer.wordnik.com/) into an environment variable **WORDNIK**
44 |
45 | As for getting the ANSI color escape codes to work, [Cmder](http://cmder.net/) seems to be the easiest way. It doesn't install a full linux environment like Cygwin, but you can still use some linux commands like **which**, **cat**, and **ls**.
46 |
47 | ## Usage
48 |
49 | leximaven has a built-in help system for CLI parameters and options. Access it with `leximaven -h|--help [command] [subcommand]`. There is also the [wiki](https://github.com/drawnepicenter/leximaven/wiki).
50 |
51 | Here are some examples:
52 |
53 | // Get definitions for 'catharsis'
54 | leximaven wordnik define catharsis
55 |
56 | // Get antonyms for 'noise'
57 | leximaven wordnik relate --canon --type antonym noises
58 |
59 | // Pronounce 'quixotic'
60 | leximaven wordnik pronounce quixotic
61 |
62 | // Get etymology for 'special'
63 | leximaven wordnik origin special
64 |
65 | // Get words that sound like 'blue'
66 | leximaven datamuse get sl=blue
67 |
68 | // Get slang/colloquialisms for 'diesel'
69 | leximaven urban diesel
70 |
71 | // Get anagrams with at least 2 letters in each word and a maximum of 3 words
72 | // per anagram using short form flags and exporting to JSON
73 | leximaven anagram -n2 -w3 -o anagrams.json toomanysecrets
74 |
75 | // Get a wordmap for 'ubiquity'
76 | leximaven wordmap ubiquity
77 |
78 | ## Resources
79 |
80 | The following links can help you use leximaven or perform related tasks.
81 |
82 | - [alex](https://github.com/wooorm/alex) Checks your writing for words or phrasings that might offend someone
83 | - [proselint](https://github.com/amperser/proselint) checks your writing style and has plugins for multiple editors
84 | - [retext](https://github.com/wooorm/retext) is a framework for natural language processing
85 | - [write-good](https://github.com/btford/write-good) Naive linter for English prose for developers who can't write good and wanna learn to do other stuff good too
86 | - ISO 639-1 [Language Codes](http://www.loc.gov/standards/iso639-2/php/English_list.php) for Rhymebrain functions
87 | - [Arpabet](http://en.wikipedia.org/wiki/Arpabet) phoneme list and [IPA](http://en.wikipedia.org/wiki/Help:IPA_for_English) equivalents
88 | - [Dewey Decimal Classes](http://en.wikipedia.org/wiki/List_of_Dewey_Decimal_classes) for acronyms
89 | - Browse Datamuse's Onelook [dictionaries](http://www.onelook.com/?d=all_gen), use its [dictionary lookup](http://www.onelook.com/), [thesaurus/reverse lookup](http://www.onelook.com/thesaurus/), and [RhymeZone](http://www.rhymezone.com/)
90 |
91 | ## Contributing
92 |
93 | See [CONTRIBUTING](https://github.com/drawnepicenter/leximaven/blob/master/CONTRIBUTING.md).
94 |
95 | ## License
96 |
97 | MIT :copyright: 2017-2019 Andrew Prentice
98 |
99 | ## Powered by
100 |
101 | Acronym Server, Datamuse, Onelook, Rhymebrain, Urban Dictionary, and Wordnik
102 |
103 | ## Extras
104 |
105 | ### Prose
106 |
107 | For fun, read some of my [prose](https://github.com/drawnepicenter/prose#readme)...
108 |
109 | ### Take Command
110 |
111 | See [take-command](https://github.com/drawnepicenter/take-command).
112 |
--------------------------------------------------------------------------------
/bin/commands/acronym.js:
--------------------------------------------------------------------------------
1 | 'use strict';var themes=require('../themes');var tools=require('../tools');var _=require('lodash');var chalk=require('chalk');var http=require('good-guy-http')();var noon=require('noon');var xml2js=require('xml2js');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='acronym ';exports.aliases=['acro','ac'];exports.desc='Acronyms';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Acronyms');var acronym=argv.acronym.toUpperCase();var url='http://acronyms.silmaril.ie/cgi-bin/xaa?'+argv.acronym;var tofile={type:'acronym',source:'http://acronyms.silmaril.ie',url:url};var ctstyle=_.get(chalk,theme.content.style);http({url:url},function(error,response){if(!error&&response.statusCode===200){var body=response.body;var parser=new xml2js.Parser();parser.parseString(body,function(err,result){if(!err){var found=result.acronym.found[0];var count=found.$;if(count.n==='0'){console.log(ctstyle('Found 0 acronyms for '+acronym+'.'));}else{console.log(ctstyle('Found '+count.n+' acronyms for '+acronym+':'));var list=found.acro;for(var i=0;i<=list.length-1;i++){var item=list[i];process.stdout.write(ctstyle(''+item.expan));tofile[['expansion'+i]]=item.expan[0];var comm=item.comment[0];if(comm!==''){if(comm.a){var comment=comm.a[0];process.stdout.write(ctstyle(' - '+comment._+' - '+comment.$.href));tofile[['comment'+i]]=comment._;tofile[['url'+i]]=comment.$.href;}else{process.stdout.write(ctstyle(' - '+comm));tofile[['comment'+i]]=item.comment[0];}}console.log(ctstyle(' - DDC: '+item.$.dewey));tofile[['DDC'+i]]=item.$.dewey;}if(argv.o)tools.outFile(argv.o,argv.f,tofile);}}else{throw new Error(err);}});}else{throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);}});};
--------------------------------------------------------------------------------
/bin/commands/completion.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint no-unused-vars:0, no-unused-expressions:0 */var yargs=require('yargs');exports.command='completion';exports.aliases=['comp'];exports.desc='Print shell completion script';exports.builder={};exports.handler=function(argv){yargs.showCompletionScript().argv;};
--------------------------------------------------------------------------------
/bin/commands/configuration.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint no-unused-vars: 0 */exports.command='configuration ';exports.aliases=['conf','config'];exports.desc='Configuration tasks';exports.builder=function(yargs){return yargs.commandDir('configuration');};exports.handler=function(argv){};
--------------------------------------------------------------------------------
/bin/commands/configuration/get.js:
--------------------------------------------------------------------------------
1 | 'use strict';var themes=require('../../themes');var tools=require('../../tools');var chalk=require('chalk');var dot=require('dot-prop');var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='get ';exports.aliases=['g'];exports.desc='Retrieve a config value';exports.builder={};exports.handler=function(argv){var key=argv.key;var value=null;tools.checkConfig(CFILE);var config=noon.load(CFILE);var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Configuration');if(dot.has(config,key)){value=/\./i.test(key)?dot.get(config,key):config[key];}else{throw new Error('Option '+key+' not found.');}console.log('Option '+chalk.white.bold(key)+' is '+chalk.white.bold(value)+'.');};
--------------------------------------------------------------------------------
/bin/commands/configuration/init.js:
--------------------------------------------------------------------------------
1 | 'use strict';var themes=require('../../themes');var chalk=require('chalk');var fs=require('fs');var noon=require('noon');var os=require('os');var CFILE=process.env.HOME+'/.leximaven.noon';var PKGDIR=process.env.NODE_PATH+'/leximaven/';exports.command='init';exports.aliases=['i'];exports.desc='Initialize config file';exports.builder={force:{alias:'f',desc:'Force overwriting configuration file',default:false,type:'boolean'}};exports.handler=function(argv){var obj=null;var configExists=null;var dirExists=null;try{fs.statSync('default.config.noon');configExists=true;}catch(e){if(e.code==='ENOENT')configExists=false;}if(configExists){obj=noon.load('default.config.noon');}else{try{fs.statSync(PKGDIR);dirExists=true;}catch(e){if(e.code==='ENOENT'){dirExists=false;}}if(dirExists){obj=noon.load(PKGDIR+'default.config.noon');}else{throw new Error('Package dir not found, set NODE_PATH per documentation.');}}obj.dmuse.date.stamp=new Date().toJSON();obj.onelook.date.stamp=new Date().toJSON();obj.rbrain.date.stamp=new Date().toJSON();obj.wordnik.date.stamp=new Date().toJSON();var fileExists=null;try{fs.statSync(CFILE);fileExists=true;}catch(e){if(e.code==='ENOENT'){fileExists=false;}}if(fileExists){if(argv.f){var _config=noon.load(CFILE);obj.dmuse.date.stamp=_config.dmuse.date.stamp;obj.dmuse.date.remain=_config.dmuse.date.remain;obj.onelook.date.stamp=_config.onelook.date.stamp;obj.onelook.date.remain=_config.onelook.date.remain;obj.rbrain.date.stamp=_config.rbrain.date.stamp;obj.rbrain.date.remain=_config.rbrain.date.remain;obj.wordnik.date.stamp=_config.wordnik.date.stamp;obj.wordnik.date.remain=_config.wordnik.date.remain;noon.save(CFILE,obj);console.log('Overwrote '+chalk.white.bold(CFILE)+'.');}else{console.log('Using configuration at '+chalk.white.bold(CFILE)+'.');}}else if(!fileExists){noon.save(CFILE,obj);console.log('Created '+chalk.white.bold(CFILE)+'.');}var config=noon.load(CFILE);var theme=themes.loadTheme(config.theme);if(os.platform()==='windows')themes.label(theme,'right','Notice','Please see the README for best user experience on Windows.');if(argv.v){themes.label(theme,'down','Configuration');console.log('Your current configuration is:');console.log(noon.stringify(config,{indent:2,align:true,maxalign:32,sort:true,colors:true}));console.log('');}};
--------------------------------------------------------------------------------
/bin/commands/configuration/set.js:
--------------------------------------------------------------------------------
1 | 'use strict';var themes=require('../../themes');var tools=require('../../tools');var chalk=require('chalk');var dot=require('dot-prop');var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='set ';exports.aliases=['s'];exports.desc='Set a config value';exports.builder={};exports.handler=function(argv){var key=argv.key;var value=argv.value;value=tools.checkBoolean(value);tools.checkConfig(CFILE);var config=noon.load(CFILE);var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Configuration');if(dot.has(config,key)){if(/\./i.test(key)){if(/^\w*\.date/i.test(key)){throw new Error("API limits hardcoded, can't set this key.");}else{dot.set(config,key,value);}}else{config[key]=value;}}else{throw new Error('Option '+key+' not found.');}noon.save(CFILE,config);console.log('Set option '+chalk.white.bold(key)+' to '+chalk.white.bold(value)+'.');};
--------------------------------------------------------------------------------
/bin/commands/datamuse.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint no-unused-vars: 0 */exports.command='datamuse ';exports.aliases=['dmuse','dm'];exports.desc='Datamuse tasks';exports.builder=function(yargs){return yargs.commandDir('datamuse');};exports.handler=function(argv){};
--------------------------------------------------------------------------------
/bin/commands/datamuse/get.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var df=require('date-fns');var chalk=require('chalk');var http=require('good-guy-http')();var noon=require('noon');var ora=require('ora');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='get ';exports.desc='Datamuse query';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},max:{alias:'m',desc:'Maximum number of results, 1 to 1000',default:5,type:'number'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.dmuse.date.stamp);var hours=df.differenceInHours(new Date(),stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitDmuse(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={dmuse:{max:argv.m}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Datamuse');var ccont=[];ccont.push(argv.condition);if(argv._.length>1){for(var i=0;i<=argv._.length-1;i++){if(argv._[i]!=='datamuse'&&argv._[i]!=='dmuse'&&argv._[i]!=='dm'&&argv._[i]!=='get'){ccont.push(argv._[i]);}}}var prefix='http://api.datamuse.com/words?';var conditions='max='+config.dmuse.max+'&';for(var _i=0;_i<=ccont.length-1;_i++){conditions=conditions+'&'+ccont[_i];}var url=''+prefix+conditions;url=encodeURI(url);var tags={n:'noun',adj:'adjective',adv:'adverb',syn:'synonym'};var tofile={type:'datamuse',source:'http://datamuse.com/api',url:url};var ctstyle=_.get(chalk,theme.content.style);var spinner=ora({text:''+chalk.bold.cyan('Loading results...'),spinner:'dots8',color:'yellow'});http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.dmuse.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var resp=JSON.parse(response.body);spinner.stop();spinner.clear();for(var _i2=0;_i2<=resp.length-1;_i2++){var item=resp[_i2];themes.label(theme,'right','Match',item.word+' ');tofile[['match'+_i2]]=item.word;if(item.tags!==undefined&&item.tags!==[]){themes.label(theme,'right','Tag');for(var j=0;j<=item.tags.length-1;j++){if(j===item.tags.length-1){process.stdout.write(ctstyle(''+tags[item.tags[j]]));tofile[['tags'+j]]=tags[item.tags[j]];}else process.stdout.write(ctstyle(tags[item.tags[j]]+', '));}console.log('');}}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, reset usage limits.\n'+config.dmuse.date.remain+'/'+config.dmuse.date.limit+' requests remaining today.'):console.log(config.dmuse.date.remain+'/'+config.dmuse.date.limit+' requests remaining today, will reset in '+(23-hours)+' hours, '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached today\'s usage limit of '+config.dmuse.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/datamuse/info.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0, no-unused-vars:0 */var tools=require('../../tools');var chalk=require('chalk');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='info';exports.desc='Datamuse metrics';exports.builder={};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var url='http://api.datamuse.com/metrics';http({url:url},function(error,response){if(!error&&response.statusCode===200){var body=JSON.parse(response.body);var version=body[0];var qps=body[1];var sugf=body[2];var sugn=body[3];var wordf=body[4];var wordn=body[5];console.log(chalk.white('Current queries per second (v'+Math.round(version.value*100)/100.0+'): '+Math.round(qps.value*100)/100.0));console.log(chalk.white('Latency (/words): '+Math.round(wordf.value*100000)/100.0+' ms (median), '+Math.round(wordn.value*100000)/100.0+' ms (99 %ile)'));console.log(chalk.white('Latency (/sug): '+Math.round(sugf.value*100000)/100.0+' ms (median), '+Math.round(sugn.value*100000)/100.0+' ms (99 %ile)'));}else{throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);}});var limit=config.dmuse.date.limit;var remain=config.dmuse.date.remain;var stamp=new Date(config.dmuse.date.stamp);var hours=df.differenceInHours(new Date(),stamp);var minutes=df.differenceInMinutes(new Date(),stamp);console.log(chalk.white(remain+'/'+limit+' requests remain today, will reset in '+(23-hours)+' hours, '+(59-minutes)+' minutes.'));};
--------------------------------------------------------------------------------
/bin/commands/list.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint no-unused-vars: 0 */var themes=require('../themes');exports.command='list';exports.aliases=['ls','themes'];exports.desc='Get a list of installed themes';exports.builder={};exports.handler=function(argv){var list=themes.getThemes();for(var i=0;i<=list.length-1;i++){var currentTheme=themes.loadTheme(list[i]);var sample='Morbi ornare pulvinar metus, non faucibus arcu ultricies non.';themes.label(currentTheme,'down',list[i],sample);}};
--------------------------------------------------------------------------------
/bin/commands/onelook.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../themes');var tools=require('../tools');var _=require('lodash');var df=require('date-fns');var chalk=require('chalk');var http=require('good-guy-http')();var noon=require('noon');var xml2js=require('xml2js');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='onelook ';exports.aliases=['one','ol'];exports.desc='Onelook definitions';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},links:{alias:'l',desc:'Include resource links',default:false,type:'boolean'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var checkStamp=tools.limitOnelook(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];var stamp=new Date(config.onelook.date.stamp);var hours=df.differenceInHours(new Date(),stamp);var minutes=df.differenceInMinutes(new Date(),stamp);if(proceed){var userConfig={onelook:{links:argv.l}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Onelook');var acont=[];acont.push(argv.word);if(argv._.length>1){for(var i=0;i<=argv._.length-1;i++){if(argv._[i]!=='onelook'&&argv._[i]!=='one'&&argv._[i]!=='ol')acont.push(argv._[i]);}}var url='http://onelook.com/?xml=1&w='+acont.join('+');url=encodeURI(url);var tofile={type:'onelook',source:'http://www.onelook.com',url:url};var ctstyle=_.get(chalk,theme.content.style);http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.onelook.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var body=response.body;var parser=new xml2js.Parser();parser.parseString(body,function(err,result){if(!err){var resp=result.OLResponse;var phrase=resp.OLPhrases[0];var similar=resp.OLSimilar[0];var quickdef=resp.OLQuickDef;var resources=resp.OLRes;themes.label(theme,'down','Definition');if(Array.isArray(quickdef)&&quickdef.length>1){for(var _i=0;_i<=quickdef.length-1;_i++){var item=quickdef[_i];item=item.replace(/<|>|\n|\/i/g,'');item=item.replace(/i"/g,'"');console.log(ctstyle(item));tofile[['definition'+_i]]=item;}}else{var definition=quickdef[0].replace(/<|>|\n|\/i/g,'');console.log(ctstyle(definition));tofile.definition=definition;}if(phrase){var phrases=phrase.replace(/\n/g,'');themes.label(theme,'down','Phrases',phrases);tofile.phrase=phrases;}if(similar){var sim=similar.replace(/\n/g,'');themes.label(theme,'down','Similar',sim);tofile.sim=sim;}if(config.onelook.links){themes.label(theme,'down','Resources');for(var _i2=0;_i2<=resources.length-1;_i2++){var _item=resources[_i2];var res=tools.arrToStr(_item.OLResName).replace(/\n/g,'');var link=tools.arrToStr(_item.OLResLink).replace(/\n/g,'');var home=tools.arrToStr(_item.OLResHomeLink).replace(/\n/g,'');themes.label(theme,'right',res,link);tofile[['res'+_i2]]=res;tofile[['link'+_i2]]=link;tofile[['home'+_i2]]=home;}}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage){if(reset){console.log('Timestamp expired, reset usage limits.');console.log(config.onelook.date.remain+'/'+config.onelook.date.limit+' requests remaining today.');}else console.log(config.onelook.date.remain+'/'+config.onelook.date.limit+' requests remaining today, will reset in '+(23-hours)+' hours, '+(59-minutes)+' minutes.');}}else{throw new Error(err);}});}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached today\'s usage limit of '+config.onelook.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/random.js:
--------------------------------------------------------------------------------
1 | 'use strict';var rand=require('random-word');exports.command='random';exports.aliases=['rand','rw'];exports.desc='Get a random word';exports.builder={};exports.handler=function(argv){console.log(rand());};
--------------------------------------------------------------------------------
/bin/commands/rhymebrain.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint no-unused-vars: 0 */exports.command='rhymebrain ';exports.aliases=['rbrain','rb'];exports.desc='Rhymebrain operations';exports.builder=function(yargs){return yargs.commandDir('rhymebrain');};exports.handler=function(argv){};
--------------------------------------------------------------------------------
/bin/commands/rhymebrain/combine.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='combine ';exports.aliases=['comb','portmanteau'];exports.desc='Rhymebrain portmanteaus';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},lang:{alias:'l',desc:'ISO 639-1 language code',default:'en',type:'string'},max:{alias:'m',desc:'Max results to return',default:5,type:'number'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.rbrain.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitRbrain(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={rbrain:{combine:{lang:argv.l,max:argv.m}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Rhymebrain');var query=argv.query;var task='Portmanteaus';var prefix='http://rhymebrain.com/talk?function=get';var uri=''+prefix+task+'&word='+query+'&';var pcont=[];pcont.push('lang='+config.rbrain.combine.lang+'&');pcont.push('maxResults='+config.rbrain.combine.max+'&');var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);themes.label(theme,'down',task);var tofile={type:'portmanteau',source:'http://rhymebrain.com',url:url};http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.rbrain.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var list=JSON.parse(response.body);for(var i=0;i<=list.length-1;i++){var item=list[i];themes.label(theme,'right',item.source,item.combined);tofile[['set'+i]]=item.source;tofile[['portmanteau'+i]]=item.combined;}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, reset usage limits.\n'+config.rbrain.date.remain+'/'+config.rbrain.date.limit+' requests remaining this hour.'):console.log(config.rbrain.date.remain+'/'+config.rbrain.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.rbrain.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/rhymebrain/info.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var chalk=require('chalk');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='info ';exports.desc='Rhymebrain word info';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},lang:{alias:'l',desc:'ISO 639-1 language code',default:'en',type:'string'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.rbrain.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitRbrain(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={rbrain:{info:{lang:argv.l}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Rhymebrain');var word=argv.word;var task='WordInfo';var prefix='http://rhymebrain.com/talk?function=get';var uri=''+prefix+task+'&word='+word+'&lang='+config.rbrain.info.lang;var url=encodeURI(uri);themes.label(theme,'down','Word Info');var tofile={type:'word info',source:'http://rhymebrain.com',url:url};var ctstyle=_.get(chalk,theme.content.style);http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.rbrain.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var info=JSON.parse(response.body);themes.label(theme,'right','Arpabet',info.pron);themes.label(theme,'right','IPA',info.ipa);themes.label(theme,'right','Syllables',info.syllables);tofile.arpabet=info.pron;tofile.ipa=info.ipa;tofile.syllables=info.syllables;var flags=[];if(info.flags.match(/a/)){flags.push(ctstyle('['+chalk.red.bold('Offensive')+']'));tofile.offensive=true;}if(info.flags.match(/b/)){flags.push(ctstyle('[Found in dictionary]'));tofile.dict=true;}if(info.flags.match(/c/)){flags.push(ctstyle('[Trusted pronunciation, not generated]'));tofile.trusted=true;}themes.label(theme,'right','Word Flags',flags.join(''));if(argv.o)tools.outFile(argv.o,argv.f,tofile);reset?console.log('Timestamp expired, reset usage limits.\n'+config.rbrain.date.remain+'/'+config.rbrain.date.limit+' requests remaining this hour.'):console.log(config.rbrain.date.remain+'/'+config.rbrain.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.rbrain.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/rhymebrain/rhyme.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var chalk=require('chalk');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='rhyme ';exports.aliases=['rh'];exports.desc='Rhymebrain rhymes';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},lang:{alias:'l',desc:'ISO 639-1 language code',default:'en',type:'string'},max:{alias:'m',desc:'Max results to return',default:5,type:'number'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.rbrain.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitRbrain(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={rbrain:{rhyme:{lang:argv.l,max:argv.m}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Rhymebrain');var word=argv.word;var task='Rhymes';var prefix='http://rhymebrain.com/talk?function=get';var uri=''+prefix+task+'&word='+word+'&';var pcont=[];pcont.push('lang='+config.rbrain.rhyme.lang+'&');pcont.push('maxResults='+config.rbrain.rhyme.max+'&');var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);var tofile={type:'rhyme',source:'http://rhymebrain.com',url:url};var ctstyle=_.get(chalk,theme.content.style);http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.rbrain.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var list=JSON.parse(response.body);var lcont=[];for(var i=0;i<=list.length-1;i++){lcont.push(list[i].word);}lcont.sort(function(a,b){if(ab)return 1;return 0;});var rcont=[];for(var j=0;j<=lcont.length-1;j++){var item=lcont[j];rcont.push(ctstyle(item));item.score>=300?tofile[['hiscore'+j]]=item:tofile[['rhyme'+j]]=item;}rcont.sort();themes.label(theme,'right',task,rcont.join(', '));if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, reset usage limits.\n'+config.rbrain.date.remain+'/'+config.rbrain.date.limit+' requests remaining this hour.'):console.log(config.rbrain.date.remain+'/'+config.rbrain.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.rbrain.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/urban.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../themes');var tools=require('../tools');var _=require('lodash');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='urban ';exports.aliases=['urb','slang'];exports.desc='Urban Dictionary definitions';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},limit:{alias:'l',desc:'Limit number of results',default:5,type:'number'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var userConfig={urban:{limit:argv.l}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Urban Dictionary');var ucont=[];ucont.push(argv.query);if(argv._.length>1){for(var i=0;i<=argv._.length-1;i++){if(argv._[i]!=='urban'&&argv._[i]!=='urb'&&argv._[i]!=='slang')ucont.push(argv._[i]);}}var words='';if(ucont.length>1){words=ucont.join('+');}else{words=ucont[0];}var url='http://api.urbandictionary.com/v0/define?term='+words;url=encodeURI(url);var tofile={type:'urban',source:'http://www.urbandictionary.com',url:url};http({url:url},function(error,response){if(!error&&response.statusCode===200){var body=JSON.parse(response.body);var limit=config.urban.limit;var list=body.list.slice(0,limit);for(var _i=0;_i<=list.length-1;_i++){var result=list[_i];themes.label(theme,'down','Definition',result.definition);tofile[['definition'+_i]]=result.definition;}if(argv.o)tools.outFile(argv.o,argv.f,tofile);}else{throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);}});};
--------------------------------------------------------------------------------
/bin/commands/wordmap.js:
--------------------------------------------------------------------------------
1 | 'use strict';var themes=require('../themes');var tools=require('../tools');var _=require('lodash');var child=require('child_process');var fs=require('fs');var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='wordmap ';exports.aliases=['map','wm'];exports.desc='Maps of word info';exports.builder={limit:{alias:'l',desc:'Limits the number of results',default:1,type:'number'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'}};exports.handler=function(argv){tools.checkConfig(CFILE);var config=noon.load(CFILE);var userConfig={wordmap:{limit:argv.l}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordmap');var word=argv.word;var l=argv.l;var bin='';var dirExists=null;try{fs.statSync('bin/leximaven.js');dirExists=true;}catch(e){if(e.code==='ENOENT')dirExists=false;}dirExists?bin='bin/leximaven.js':bin=process.env.NODE_PATH+'/leximaven/bin/leximaven.js';child.spawnSync('node',[bin,'rbrain','combine','-m'+l,''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'rbrain','info',''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'rbrain','rhyme','-m'+l,''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'wordnik','define','-l'+l,''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'wordnik','example','-l'+l,''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'wordnik','hyphen',''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'wordnik','origin',''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'wordnik','phrase','-l'+l,''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'wordnik','pronounce','-l'+l,''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'wordnik','relate','-l'+l,''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'acronym',''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'dmuse','-m'+l,'ml='+word],{stdio:'inherit'});child.spawnSync('node',[bin,'onelook',''+word],{stdio:'inherit'});child.spawnSync('node',[bin,'urban','-l'+l,''+word],{stdio:'inherit'});// child.spawnSync('node', [bin, 'anagram', `-t${l}`, `${word}`], { stdio: 'inherit' })
2 | };
--------------------------------------------------------------------------------
/bin/commands/wordnik.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint no-unused-vars: 0 */exports.command='wordnik ';exports.aliases=['wnik','wn'];exports.desc='Wordnik tasks';exports.builder=function(yargs){return yargs.commandDir('wordnik');};exports.handler=function(argv){};
--------------------------------------------------------------------------------
/bin/commands/wordnik/define.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var df=require('date-fns');var chalk=require('chalk');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='define ';exports.aliases=['def'];exports.desc='Wordnik definitions';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},limit:{alias:'l',desc:'Limit number of results',default:5,type:'number'},canon:{alias:'c',desc:'Use canonical',default:false,type:'boolean'},defdict:{alias:'d',desc:"CSV list of dictionaries or 'all'",default:'all',type:'string'},part:{alias:'p',desc:'CSV list of parts of speech. See http://developer.wordnik.com/docs.html for list of parts.',default:'',type:'string'}};exports.handler=function(argv){if(process.env.WORDNIK===undefined)throw new Error('Put an API key in environment variable WORDNIK per documentation.');tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitWordnik(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={wordnik:{define:{canon:argv.c,limit:argv.l,defdict:argv.d,part:argv.p}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordnik');var word=argv.word;var task='definitions';var prefix='http://api.wordnik.com:80/v4/word.json/';var apikey=process.env.WORDNIK;var uri=''+prefix+word+'/'+task+'?';var pcont=[];pcont.push('useCanonical='+config.wordnik.define.canon+'&');pcont.push('sourceDictionaries='+config.wordnik.define.defdict+'&');pcont.push('includeRelated=false&');pcont.push('includeTags=false&');pcont.push('limit='+config.wordnik.define.limit+'&');pcont.push('partOfSpeech='+config.wordnik.define.part+'&');pcont.push('api_key='+apikey);var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);var tofile={type:'definition',source:'http://www.wordnik.com'};var cstyle=_.get(chalk,theme.connector.style);var ctstyle=_.get(chalk,theme.content.style);var uline=_.get(chalk,theme.content.style+'.underline');var conn=cstyle(theme.connector.str);http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.wordnik.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var list=JSON.parse(response.body);for(var i=0;i<=list.length-1;i++){var item=list[i];var icont=[];icont.push(ctstyle(item.text+' '));icont.push(uline(item.partOfSpeech));icont.push(conn);icont.push(ctstyle(item.sourceDictionary));themes.label(theme,'right','Definition',icont.join(''));tofile[['text'+i]]=item.text;tofile[['deftype'+i]]=item.partOfSpeech;tofile[['source'+i]]=item.sourceDictionary;}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, not decrementing usage.\n'+config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour.'):console.log(config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.wordnik.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/wordnik/example.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='example ';exports.aliases=['ex'];exports.desc='Wordnik examples';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},limit:{alias:'l',desc:'Limit number of results',default:5,type:'number'},canon:{alias:'c',desc:'Use canonical',default:false,type:'boolean'},skip:{alias:'k',desc:'Number of results to skip',default:0,type:'number'}};exports.handler=function(argv){if(process.env.WORDNIK===undefined)throw new Error('Put an API key in environment variable WORDNIK per documentation.');tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitWordnik(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={wordnik:{example:{canon:argv.c,limit:argv.l,skip:argv.k}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordnik');var word=argv.word;var task='examples';var prefix='http://api.wordnik.com:80/v4/word.json/';var apikey=process.env.WORDNIK;var uri=''+prefix+word+'/'+task+'?';var pcont=[];pcont.push('useCanonical='+config.wordnik.example.canon+'&');pcont.push('includeDuplicates=false&');pcont.push('limit='+config.wordnik.example.limit+'&');!config.wordnik.example.skip?pcont.push('skip=0&'):pcont.push('skip='+config.wordnik.example.skip+'&');pcont.push('api_key='+apikey);var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);var tofile={type:'example',source:'http://www.wordnik.com'};http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.wordnik.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var body=JSON.parse(response.body);var list=body.examples;for(var i=0;i<=list.length-1;i++){var item=list[i];themes.label(theme,'right','Example',item.text);tofile[['example'+i]]=item.text;}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, not decrementing usage.\n'+config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour.'):console.log(config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.wordnik.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/wordnik/hyphen.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var chalk=require('chalk');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='hyphen ';exports.aliases=['hyphenate','hy'];exports.desc='Wordnik hyphenations';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},limit:{alias:'l',desc:'Limit number of results',default:5,type:'number'},canon:{alias:'c',desc:'Use canonical',default:false,type:'boolean'},dict:{alias:'d',desc:'Source dictionary ahd, century, wiktionary, webster, wordnet',default:'all',type:'string'}};exports.handler=function(argv){if(process.env.WORDNIK===undefined)throw new Error('Put an API key in environment variable WORDNIK per documentation.');tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitWordnik(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={wordnik:{hyphen:{canon:argv.c,dict:argv.d,limit:argv.l}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordnik');var word=argv.word;var task='hyphenation';var prefix='http://api.wordnik.com:80/v4/word.json/';var apikey=process.env.WORDNIK;var uri=''+prefix+word+'/'+task+'?';var pcont=[];pcont.push('useCanonical='+config.wordnik.hyphen.canon+'&');if(argv.d!=='all')pcont.push('sourceDictionary='+config.wordnik.hyphen.dict+'&');pcont.push('limit='+config.wordnik.hyphen.limit+'&');pcont.push('api_key='+apikey);var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);var tofile={type:'hyphenation',source:'http://www.wordnik.com'};var ctstyle=_.get(chalk,theme.content.style);http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.wordnik.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var list=JSON.parse(response.body);var hcont=[];for(var i=0;i<=list.length-1;i++){var item=list[i];if(item.type==='stress'){hcont.push(''+chalk.red.bold(item.text));tofile[['stress'+i]]=item.text;}else if(item.type==='secondary stress'){hcont.push(ctstyle(item.text));tofile[['secondary'+i]]=item.text;}else{hcont.push(ctstyle(item.text));tofile[['syllable'+i]]=item.text;}if(i';exports.aliases=['or','etymology'];exports.desc='Wordnik etymologies';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},canon:{alias:'c',desc:'Use canonical',default:false,type:'boolean'}};exports.handler=function(argv){if(process.env.WORDNIK===undefined)throw new Error('Put an API key in environment variable WORDNIK per documentation.');tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitWordnik(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={wordnik:{origin:{canon:argv.c}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordnik');var word=argv.word;var task='etymologies';var prefix='http://api.wordnik.com:80/v4/word.json/';var apikey=process.env.WORDNIK;var uri=''+prefix+word+'/'+task+'?';var pcont=[];pcont.push('useCanonical='+config.wordnik.origin.canon+'&');pcont.push('api_key='+apikey);var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);var parser=new xml2js.Parser();var tofile={type:'etymology',source:'http://www.wordnik.com'};var ctstyle=_.get(chalk,theme.content.style);http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.wordnik.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var resp=JSON.parse(response.body);var origin=resp[0];parser.parseString(origin,function(err,result){if(!err){var root=result.ety;var content=root._;var ets=root.ets;ets=ets.join(', ');themes.label(theme,'right','Etymology',ctstyle(content+' '+ets));tofile.etymology=content;tofile.origin=ets;}else{throw new Error(err);}});if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, not decrementing usage.\n'+config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour.'):console.log(config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.wordnik.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/wordnik/phrase.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='phrase ';exports.aliases=['ph','ngram'];exports.desc='Wordnik bi-gram phrases';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},limit:{alias:'l',desc:'Limit number of results',default:5,type:'number'},canon:{alias:'c',desc:'Use canonical',default:false,type:'boolean'},weight:{alias:'w',desc:'Minimum weighted mutual info',default:13,type:'number'}};exports.handler=function(argv){if(process.env.WORDNIK===undefined)throw new Error('Put an API key in environment variable WORDNIK per documentation.');tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitWordnik(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={wordnik:{phrase:{canon:argv.c,limit:argv.l,weight:argv.w}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordnik');var word=argv.word;var task='phrases';var prefix='http://api.wordnik.com:80/v4/word.json/';var apikey=process.env.WORDNIK;var uri=''+prefix+word+'/'+task+'?';var pcont=[];pcont.push('useCanonical='+argv.c+'&');pcont.push('limit='+argv.l+'&');pcont.push('wlmi='+argv.w+'&');pcont.push('api_key='+apikey);var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);themes.label(theme,'down','Bi-gram phrases');var tofile={type:'phrase',source:'http://www.wordnik.com'};http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.wordnik.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var list=JSON.parse(response.body);for(var i=0;i<=list.length-1;i++){var item=list[i];console.log(item.gram1+' '+item.gram2);tofile[['agram'+i]]=item.gram1;tofile[['bgram'+i]]=item.gram2;}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, not decrementing usage.\n'+config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour.'):console.log(config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.wordnik.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/wordnik/pronounce.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='pronounce ';exports.aliases=['pr'];exports.desc='Wordnik pronunciations';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},limit:{alias:'l',desc:'Limit number of results',default:5,type:'number'},canon:{alias:'c',desc:'Use canonical',default:false,type:'boolean'},dict:{alias:'d',desc:'Dictionary: ahd, century, cmu, macmillan, wiktionary, webster, wordnet',default:'',type:'string'},type:{alias:'t',desc:'Type: ahd, arpabet, gcide-diacritical, ipa',default:'',type:'string'}};exports.handler=function(argv){if(process.env.WORDNIK===undefined)throw new Error('Put an API key in environment variable WORDNIK per documentation.');tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitWordnik(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={wordnik:{pronounce:{canon:argv.c,dict:argv.d,type:argv.t,limit:argv.l}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordnik');var word=argv.word;var task='pronunciations';var prefix='http://api.wordnik.com:80/v4/word.json/';var apikey=process.env.WORDNIK;var uri=''+prefix+word+'/'+task+'?';var pcont=[];pcont.push('useCanonical='+config.wordnik.pronounce.canon+'&');if(config.wordnik.pronounce.dict!=='')pcont.push('sourceDictionary='+config.wordnik.pronounce.dict+'&');if(config.wordnik.pronounce.type!=='')pcont.push('typeFormat='+config.wordnik.pronounce.type+'&');pcont.push('limit='+config.wordnik.pronounce.limit+'&');pcont.push('api_key='+apikey);var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);themes.label(theme,'down','Pronunciations');var tofile={type:'pronunciation',source:'http://www.wordnik.com'};tofile.word=word;http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.wordnik.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var list=JSON.parse(response.body);for(var i=0;i<=list.length-1;i++){var item=list[i];themes.label(theme,'right',word,item.raw+' - Type - '+item.rawType);tofile[['pronunciation'+i]]=item.raw;tofile[['type'+i]]=item.rawType;}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, not decrementing usage.\n'+config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour.'):console.log(config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.wordnik.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/commands/wordnik/relate.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var themes=require('../../themes');var tools=require('../../tools');var _=require('lodash');var df=require('date-fns');var http=require('good-guy-http')();var noon=require('noon');var CFILE=process.env.HOME+'/.leximaven.noon';exports.command='relate ';exports.aliases=['related','rel'];exports.desc='Wordnik related words';exports.builder={out:{alias:'o',desc:'Write cson, json, noon, plist, yaml, xml',default:'',type:'string'},force:{alias:'f',desc:'Force overwriting outfile',default:false,type:'boolean'},save:{alias:'s',desc:'Save flags to config file',default:false,type:'boolean'},limit:{alias:'l',desc:'Limit results = require(type option',default:10,type:'number'},canon:{alias:'c',desc:'Use canonical',default:false,type:'boolean'},type:{alias:'t',desc:'Relationship types to limit',default:'',type:'string'}};exports.handler=function(argv){if(process.env.WORDNIK===undefined)throw new Error('Put an API key in environment variable WORDNIK per documentation.');tools.checkConfig(CFILE);var config=noon.load(CFILE);var proceed=false;var reset=false;var stamp=new Date(config.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);var checkStamp=tools.limitWordnik(config);config=checkStamp[0];proceed=checkStamp[1];reset=checkStamp[2];if(proceed){var userConfig={wordnik:{relate:{canon:argv.c,type:argv.t,limit:argv.l}}};if(config.merge)config=_.merge({},config,userConfig);if(argv.s&&config.merge)noon.save(CFILE,config);if(argv.s&&!config.merge)throw new Error("Can't save user config, set option merge to true.");var theme=themes.loadTheme(config.theme);if(config.verbose)themes.label(theme,'down','Wordnik');var word=argv.word;var task='relatedWords';var prefix='http://api.wordnik.com:80/v4/word.json/';var apikey=process.env.WORDNIK;var uri=''+prefix+word+'/'+task+'?';var pcont=[];pcont.push('useCanonical='+config.wordnik.relate.canon+'&');if(config.wordnik.relate.type!=='')pcont.push('relationshipTypes='+config.wordnik.relate.type+'&');pcont.push('limitPerRelationshipType='+config.wordnik.relate.limit+'&');pcont.push('api_key='+apikey);var rest=pcont.join('');var url=''+uri+rest;url=encodeURI(url);themes.label(theme,'down','Related words');var tofile={type:'related words',source:'http://www.wordnik.com'};tofile.word=word;http({url:url},function(error,response){if(!error&&response.statusCode===200){if(response.headers['x-gg-state']==='cached'){config.wordnik.date.remain++;noon.save(CFILE,config);if(config.usage)console.log('Cached response, not decrementing usage.');}var list=JSON.parse(response.body);for(var i=0;i<=list.length-1;i++){var item=list[i];themes.label(theme,'right',item.relationshipType,''+item.words.join(', '));tofile[['type'+i]]=item.relationshipType;tofile[['words'+i]]=item.words.join(', ');}if(argv.o)tools.outFile(argv.o,argv.f,tofile);if(config.usage)reset?console.log('Timestamp expired, not decrementing usage.\n'+config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour.'):console.log(config.wordnik.date.remain+'/'+config.wordnik.date.limit+' requests remaining this hour, will reset in '+(59-minutes)+' minutes.');}else throw new Error('HTTP '+error.statusCode+': '+error.reponse.body);});}else throw new Error('Reached this hour\'s usage limit of '+config.wordnik.date.limit+'.');};
--------------------------------------------------------------------------------
/bin/leximaven.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';/* eslint max-len: 0, no-unused-expressions: 0 */var chalk=require('chalk');var pkg=require('../package.json');var yargonaut=require('yargonaut').style('bold.underline','Commands:').style('bold.underline','Options:').style('bold.cyan','boolean').style('bold.yellow','string').style('bold.magenta','number').style('bold.blue','default:').style('bold.green','aliases:');var yargs=require('yargs');yargs.commandDir('commands').usage(chalk.yellow(''+yargonaut.asFont('leximaven','Small Slant'))+'\n'+chalk.bold.underline('Usage:')+'\n$0 [options]').help('h').alias('h','help').option('v',{alias:'verbose',type:'boolean',desc:'Verbose output'}).version('V','Show current version',pkg.version).alias('V','version').global('v').demand(1).argv;
--------------------------------------------------------------------------------
/bin/themes.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len:0 */var _=require('lodash');var chalk=require('chalk');var fs=require('fs');var glob=require('glob');var noon=require('noon');var TDIR=null;var themeDirExists=null;try{fs.statSync('themes');themeDirExists=true;}catch(e){if(e.code==='ENOENT')themeDirExists=false;}themeDirExists?TDIR='themes/':TDIR=process.env.NODE_PATH+'/leximaven/themes/';/**
2 | * The themes module provides useful repetitive theme tasks
3 | * @module Themes
4 | *//**
5 | * Loads theme
6 | * @public
7 | * @param {string} theme The name of the theme
8 | * @return {Object} load The style to use
9 | */exports.loadTheme=function(theme){var dirExists=null;var load=null;try{fs.statSync('themes');dirExists=true;}catch(e){if(e.code==='ENOENT')dirExists=false;}var CFILE=process.env.HOME+'/.leximaven.noon';var config=noon.load(CFILE);if(!dirExists&&config.verbose)console.log(chalk.white(process.cwd()+'/themes does not exist, falling back to '+process.env.NODE_PATH+'/leximaven/themes.'));load=noon.load(''+TDIR+theme+'.noon');return load;};/**
10 | * Gets themes for list command
11 | * @public
12 | * @return {Array} List of theme names
13 | */exports.getThemes=function(){var list=[];var dirExists=null;var files=[];try{fs.statSync('themes');dirExists=true;}catch(e){if(e.code==='ENOENT')dirExists=false;}var CFILE=process.env.HOME+'/.leximaven.noon';var config=noon.load(CFILE);if(!dirExists&&config.verbose)console.log(chalk.white(process.cwd()+'/themes does not exist, falling back to '+process.env.NODE_PATH+'/leximaven/themes.'));files=glob.sync(TDIR+'*.noon');for(var i=0;i<=files.length-1;i++){list.push(files[i].replace(/[a-z0-9/_.]*themes\//,'').replace(/\.noon/,''));}return list;};/**
14 | * Prints label, connector, and content
15 | * @public
16 | * @param {Object} theme The style to use
17 | * @param {string} direction 'down' or 'right'
18 | * @param {string} text The label text
19 | * @param {string} [content] The text the label points at
20 | * @return {string} The stylized string to log
21 | */exports.label=function(theme,direction,text,content){var pstyle=_.get(chalk,theme.prefix.style);var tstyle=_.get(chalk,theme.text.style);var sstyle=_.get(chalk,theme.suffix.style);var cnstyle=_.get(chalk,theme.connector.style);var ctstyle=_.get(chalk,theme.content.style);var label=''+pstyle(theme.prefix.str)+tstyle(text)+sstyle(theme.suffix.str);if(direction==='right'){content!==null&&content!==undefined?label=''+label+cnstyle(theme.connector.str)+ctstyle(content):label=''+label;}else if(direction==='down'){content!==null&&content!==undefined?label=label+'\n'+cnstyle(theme.connector.str)+ctstyle(content):label=''+label;}else{throw new Error("Unsupported label direction, use 'down' or 'right'.");}console.log(label);return label;};
--------------------------------------------------------------------------------
/bin/tools.js:
--------------------------------------------------------------------------------
1 | 'use strict';/* eslint max-len: 0 */var chalk=require('chalk');var df=require('date-fns');var fs=require('fs-extra');var noon=require('noon');var ts=require('term-size');var wrap=require('wrap-ansi');var xml2js=require('xml2js');var CFILE=process.env.HOME+'/.leximaven.noon';/**
2 | * The tools module provides useful repetitive tasks
3 | * @module Utils
4 | *//**
5 | * Onelook's API limit check
6 | * @param {Object} config The current config
7 | * @return {Array} Updated config, proceed boolean, and reset boolean
8 | */exports.limitOnelook=function(config){var c=config;var proceed=false;var reset=false;var stamp=new Date(c.onelook.date.stamp);var hours=df.differenceInHours(new Date(),stamp);if(hours<24){c.onelook.date.remain--;}else if(hours>=24){reset=true;c.onelook.date.stamp=new Date().toJSON();c.onelook.date.remain=c.onelook.date.limit;c.onelook.date.remain--;}c.onelook.date.remain<=0?c.onelook.date.remain=0:proceed=true;noon.save(CFILE,c);return[c,proceed,reset];};/**
9 | * Datamuse's API limit check
10 | * @param {Object} config The current config
11 | * @return {Array} Updated config, proceed boolean, and reset boolean
12 | */exports.limitDmuse=function(config){var c=config;var proceed=false;var reset=false;var stamp=new Date(c.dmuse.date.stamp);var hours=df.differenceInHours(new Date(),stamp);if(hours<24){c.dmuse.date.remain--;}else if(hours>=24){reset=true;c.dmuse.date.stamp=new Date().toJSON();c.dmuse.date.remain=c.dmuse.date.limit;c.dmuse.date.remain--;}c.dmuse.date.remain<=0?c.dmuse.date.remain=0:proceed=true;noon.save(CFILE,c);return[c,proceed,reset];};/**
13 | * Rhymebrain's API limit check
14 | * @param {Object} config The current config
15 | * @return {Array} Updated config, proceed boolean, and reset boolean
16 | */exports.limitRbrain=function(config){var c=config;var proceed=false;var reset=false;var stamp=new Date(c.rbrain.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);if(minutes<60){c.rbrain.date.remain--;}else if(minutes>=60){reset=true;c.rbrain.date.stamp=new Date().toJSON();c.rbrain.date.remain=c.rbrain.date.limit;c.rbrain.date.remain--;}c.rbrain.date.remain<=0?c.rbrain.date.remain=0:proceed=true;noon.save(CFILE,c);return[c,proceed,reset];};/**
17 | * Wordnik's API limit check
18 | * @param {Object} config The current config
19 | * @return {Array} Updated config, proceed boolean, and reset boolean
20 | */exports.limitWordnik=function(config){var c=config;var proceed=false;var reset=false;var stamp=new Date(c.wordnik.date.stamp);var minutes=df.differenceInMinutes(new Date(),stamp);if(minutes<60){c.wordnik.date.remain--;}else if(minutes>=60){reset=true;c.wordnik.date.stamp=new Date().toJSON();c.wordnik.date.remain=c.wordnik.date.limit;c.wordnik.date.remain--;}c.wordnik.date.remain<=0?c.wordnik.date.remain=0:proceed=true;noon.save(CFILE,c);return[c,proceed,reset];};/**
21 | * Checks if a file exists
22 | * @private
23 | * @param {string} path The filename to check.
24 | * @return {boolean} fileExists
25 | */function checkOutfile(path){var fileExists=null;try{fs.statSync(path);fileExists=true;}catch(e){if(e.code==='ENOENT')fileExists=false;}return fileExists;}/**
26 | * Converts string to boolean
27 | * @public
28 | * @param {string} value
29 | * @return {boolean} v
30 | */exports.checkBoolean=function(value){var v=value;if(v==='true')v=true;if(v==='false')v=false;return v;};/**
31 | * Converts a boolean to a 0 or 1
32 | * @param {boolean} value A boolean value
33 | * @return {integer} 0 or 1
34 | */exports.boolToBin=function(value){var r=null;value?r=1:r=0;return r;};/**
35 | * Checks if config exists. If not, prints init message and exits with error code.
36 | * @public
37 | * @param {string} file Configuration filepath
38 | */exports.checkConfig=function(file){try{fs.statSync(file);}catch(e){if(e.code==='ENOENT')throw new Error('No config found at '+file+', run: \'leximaven config init\'');}return true;};/**
39 | * Checks if object is a single string in an array
40 | * @public
41 | * @param {Object} obj Any object
42 | * @return {Object} Original object or extracted string
43 | */exports.arrToStr=function(obj){var fixed=null;Array.isArray(obj)&&obj.length===1&&typeof obj[0]==='string'?fixed=obj[0]:fixed=obj;return fixed;};/**
44 | * Strips HTML from a string
45 | * @public
46 | * @param {string} string Text with HTML tags
47 | * @return {string} Plain text string
48 | */exports.stripHTML=function(string){return string.replace(/(<([^>]+)>)/ig,'');};/**
49 | * Wraps blocks of text
50 | * @param {string} str Long string
51 | * @param {boolean} hard true, soft false
52 | * @param {boolean} wwrap true, column wrap false
53 | * @return {string} ANSI-wrapped string
54 | */exports.wrapStr=function(str,hard,wwrap){var termsize=ts();return wrap(str,termsize.columns,hard,wwrap);};/**
55 | * Handles data export to file. Supports cson, json, noon, plist, xml, yaml.
56 | * @public
57 | * @param {string} path The desired filepath and extension
58 | * @param {boolean} force Whether to force overwrite
59 | * @param {Object} tofile A numbered object of data points
60 | */exports.outFile=function(path,force,tofile){var match=path.match(/\.([a-z]*)$/i);var ext=match[1];var builder=new xml2js.Builder();if(ext==='xml'){if(checkOutfile(path)){if(force){var xml=builder.buildObject(tofile);var fd=fs.openSync(path,'w+');fs.writeSync(fd,xml);fs.closeSync(fd);console.log(chalk.white('Overwrote '+path+' with data.'));}else console.log(chalk.white(path+' exists, use -f to force overwrite.'));}else{var _xml=builder.buildObject(tofile);var _fd=fs.openSync(path,'w+');fs.writeSync(_fd,_xml);fs.closeSync(_fd);console.log(chalk.white('Wrote data to '+path+'.'));}}else if(ext==='cson'||ext==='json'||ext==='noon'||ext==='plist'||ext==='yml'||ext==='yaml'){if(checkOutfile(path)){if(force){noon.save(path,tofile);console.log(chalk.white('Overwrote '+path+' with data.'));}else console.log(chalk.white(path+' exists, use -f to force overwrite.'));}else{noon.save(path,tofile);console.log(chalk.white('Wrote data to '+path+'.'));}}else if(ext!=='xml'||ext!=='cson'||ext!=='json'||ext!=='noon'||ext!=='plist'||ext!=='yml'||ext!=='yaml')throw new Error('Format '+ext+' not supported.');};
--------------------------------------------------------------------------------
/default.config.noon:
--------------------------------------------------------------------------------
1 | anagram
2 | case 1
3 | lang english
4 | limit 10
5 | linenum false
6 | list false
7 | maxletter 50
8 | maxword 10
9 | minletter 1
10 | repeat false
11 | dmuse
12 | date
13 | interval day
14 | limit 100000
15 | remain 100000
16 | stamp ||
17 | max 5
18 | merge true
19 | onelook
20 | date
21 | interval day
22 | limit 10000
23 | remain 10000
24 | stamp ||
25 | links false
26 | rbrain
27 | combine
28 | lang en
29 | max 5
30 | date
31 | interval hour
32 | limit 350
33 | remain 350
34 | stamp ||
35 | info
36 | lang en
37 | rhyme
38 | lang en
39 | max 50
40 | theme square
41 | urban
42 | limit 5
43 | usage true
44 | verbose true
45 | wordmap
46 | limit 1
47 | wordnik
48 | date
49 | interval hour
50 | limit 15000
51 | remain 15000
52 | stamp ||
53 | define
54 | canon false
55 | defdict all
56 | limit 5
57 | part ||
58 | example
59 | canon false
60 | limit 5
61 | skip 0
62 | hyphen
63 | canon false
64 | dict all
65 | limit 5
66 | origin
67 | canon false
68 | phrase
69 | canon false
70 | limit 5
71 | weight 13
72 | pronounce
73 | canon false
74 | dict ||
75 | limit 5
76 | type ||
77 | relate
78 | canon false
79 | limit 10
80 | type ||
81 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "leximaven",
3 | "version": "4.0.0",
4 | "description": "A command line tool for searching word-related APIs.",
5 | "author": "Andrew Prentice",
6 | "license": "MIT",
7 | "config": {
8 | "commitizen": {
9 | "path": "./node_modules/cz-conventional-changelog"
10 | }
11 | },
12 | "main": "bin/leximaven.js",
13 | "bin": {
14 | "leximaven": "bin/leximaven.js"
15 | },
16 | "scripts": {
17 | "bin": "cross-env BABEL_ENV=dev babel src -d bin",
18 | "bump": "git push origin master --tags && npm publish",
19 | "instrument": "cross-env BABEL_ENV=test babel src -d bin",
20 | "lint": "standard --fix src",
21 | "release": "standard-version",
22 | "test": "echo 'No tests.'",
23 | "watch": "babel -w src -d bin"
24 | },
25 | "dependencies": {
26 | "acorn": "*",
27 | "ansi-colors": "*",
28 | "cz-conventional-changelog": "*",
29 | "date-fns": "*",
30 | "dot-prop": "*",
31 | "fs-extra": "*",
32 | "glob": "*",
33 | "good-guy-http": "*",
34 | "lodash": "*",
35 | "noon": "*",
36 | "ora": "*",
37 | "random-word": "*",
38 | "scrape-it": "*",
39 | "term-size": "*",
40 | "wrap-ansi": "*",
41 | "xml2js": "*",
42 | "yargonaut": "*",
43 | "yargs": "*"
44 | },
45 | "devDependencies": {
46 | "babel-core": "*",
47 | "babel-plugin-lodash": "*",
48 | "babel-preset-env": "*",
49 | "babel-register": "*",
50 | "cross-env": "*",
51 | "has-ansi": "*",
52 | "rimraf": "*",
53 | "standard": "*"
54 | },
55 | "repository": {
56 | "type": "git",
57 | "url": "git+https://github.com/drawnepicenter/leximaven.git"
58 | },
59 | "bugs": {
60 | "url": "https://github.com/drawnepicenter/leximaven/issues"
61 | },
62 | "homepage": "https://github.com/drawnepicenter/leximaven#readme",
63 | "keywords": [
64 | "lyracyst",
65 | "lyricist",
66 | "leximaven",
67 | "cli",
68 | "word",
69 | "search",
70 | "api",
71 | "scraper",
72 | "rest",
73 | "anagram",
74 | "acronym",
75 | "define",
76 | "dictionary",
77 | "thesaurus",
78 | "slang",
79 | "rhyme",
80 | "pronunciation"
81 | ],
82 | "packageManager": "pnpm@8.10.2+sha1.e0b68270e89c817ff88b7be62466a2128c53af02"
83 | }
84 |
--------------------------------------------------------------------------------
/src/commands/acronym.js:
--------------------------------------------------------------------------------
1 | const themes = require('../themes')
2 | const tools = require('../tools')
3 |
4 | const _ = require('lodash')
5 | const chalk = require('chalk')
6 | const http = require('good-guy-http')()
7 | const noon = require('noon')
8 | const xml2js = require('xml2js')
9 |
10 | const CFILE = `${process.env.HOME}/.leximaven.noon`
11 |
12 | exports.command = 'acronym '
13 | exports.aliases = ['acro', 'ac']
14 | exports.desc = 'Acronyms'
15 | exports.builder = {
16 | out: {
17 | alias: 'o',
18 | desc: 'Write cson, json, noon, plist, yaml, xml',
19 | default: '',
20 | type: 'string'
21 | },
22 | force: {
23 | alias: 'f',
24 | desc: 'Force overwriting outfile',
25 | default: false,
26 | type: 'boolean'
27 | }
28 | }
29 | exports.handler = (argv) => {
30 | tools.checkConfig(CFILE)
31 | const config = noon.load(CFILE)
32 | const theme = themes.loadTheme(config.theme)
33 | if (config.verbose) themes.label(theme, 'down', 'Acronyms')
34 | const acronym = argv.acronym.toUpperCase()
35 | const url = `http://acronyms.silmaril.ie/cgi-bin/xaa?${argv.acronym}`
36 | const tofile = {
37 | type: 'acronym',
38 | source: 'http://acronyms.silmaril.ie',
39 | url
40 | }
41 | const ctstyle = _.get(chalk, theme.content.style)
42 | http({ url }, (error, response) => {
43 | if (!error && response.statusCode === 200) {
44 | const body = response.body
45 | const parser = new xml2js.Parser()
46 | parser.parseString(body, (err, result) => {
47 | if (!err) {
48 | const found = result.acronym.found[0]
49 | const count = found.$
50 | if (count.n === '0') {
51 | console.log(ctstyle(`Found 0 acronyms for ${acronym}.`))
52 | } else {
53 | console.log(ctstyle(`Found ${count.n} acronyms for ${acronym}:`))
54 | const list = found.acro
55 | for (let i = 0; i <= list.length - 1; i++) {
56 | const item = list[i]
57 | process.stdout.write(ctstyle(`${item.expan}`))
58 | tofile[[`expansion${i}`]] = item.expan[0]
59 | const comm = item.comment[0]
60 | if (comm !== '') {
61 | if (comm.a) {
62 | const comment = comm.a[0]
63 | process.stdout.write(ctstyle(` - ${comment._} - ${comment.$.href}`))
64 | tofile[[`comment${i}`]] = comment._
65 | tofile[[`url${i}`]] = comment.$.href
66 | } else {
67 | process.stdout.write(ctstyle(` - ${comm}`))
68 | tofile[[`comment${i}`]] = item.comment[0]
69 | }
70 | }
71 | console.log(ctstyle(` - DDC: ${item.$.dewey}`))
72 | tofile[[`DDC${i}`]] = item.$.dewey
73 | }
74 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
75 | }
76 | } else {
77 | throw new Error(err)
78 | }
79 | })
80 | } else {
81 | throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
82 | }
83 | })
84 | }
85 |
--------------------------------------------------------------------------------
/src/commands/completion.js:
--------------------------------------------------------------------------------
1 | /* eslint no-unused-vars:0, no-unused-expressions:0 */
2 | const yargs = require('yargs')
3 | exports.command = 'completion'
4 | exports.aliases = ['comp']
5 | exports.desc = 'Print shell completion script'
6 | exports.builder = {}
7 | exports.handler = (argv) => {
8 | yargs.showCompletionScript().argv
9 | }
10 |
--------------------------------------------------------------------------------
/src/commands/configuration.js:
--------------------------------------------------------------------------------
1 | /* eslint no-unused-vars: 0 */
2 | exports.command = 'configuration '
3 | exports.aliases = ['conf', 'config']
4 | exports.desc = 'Configuration tasks'
5 | exports.builder = (yargs) => yargs.commandDir('configuration')
6 | exports.handler = (argv) => {}
7 |
--------------------------------------------------------------------------------
/src/commands/configuration/get.js:
--------------------------------------------------------------------------------
1 | const themes = require('../../themes')
2 | const tools = require('../../tools')
3 |
4 | const chalk = require('chalk')
5 | const dot = require('dot-prop')
6 | const noon = require('noon')
7 |
8 | const CFILE = `${process.env.HOME}/.leximaven.noon`
9 |
10 | exports.command = 'get '
11 | exports.aliases = ['g']
12 | exports.desc = 'Retrieve a config value'
13 | exports.builder = {}
14 | exports.handler = (argv) => {
15 | const key = argv.key
16 | let value = null
17 | tools.checkConfig(CFILE)
18 | const config = noon.load(CFILE)
19 | const theme = themes.loadTheme(config.theme)
20 | if (config.verbose) themes.label(theme, 'down', 'Configuration')
21 | if (dot.has(config, key)) {
22 | value = /\./i.test(key) ? dot.get(config, key) : config[key]
23 | } else {
24 | throw new Error(`Option ${key} not found.`)
25 | }
26 | console.log(`Option ${chalk.white.bold(key)} is ${chalk.white.bold(value)}.`)
27 | }
28 |
--------------------------------------------------------------------------------
/src/commands/configuration/init.js:
--------------------------------------------------------------------------------
1 | const themes = require('../../themes')
2 |
3 | const chalk = require('chalk')
4 | const fs = require('fs')
5 | const noon = require('noon')
6 | const os = require('os')
7 |
8 | const CFILE = `${process.env.HOME}/.leximaven.noon`
9 | const PKGDIR = `${process.env.NODE_PATH}/leximaven/`
10 |
11 | exports.command = 'init'
12 | exports.aliases = ['i']
13 | exports.desc = 'Initialize config file'
14 | exports.builder = {
15 | force: {
16 | alias: 'f',
17 | desc: 'Force overwriting configuration file',
18 | default: false,
19 | type: 'boolean'
20 | }
21 | }
22 | exports.handler = (argv) => {
23 | let obj = null
24 | let configExists = null
25 | let dirExists = null
26 | try {
27 | fs.statSync('default.config.noon')
28 | configExists = true
29 | } catch (e) {
30 | if (e.code === 'ENOENT') configExists = false
31 | }
32 | if (configExists) {
33 | obj = noon.load('default.config.noon')
34 | } else {
35 | try {
36 | fs.statSync(PKGDIR)
37 | dirExists = true
38 | } catch (e) {
39 | if (e.code === 'ENOENT') {
40 | dirExists = false
41 | }
42 | }
43 | if (dirExists) {
44 | obj = noon.load(`${PKGDIR}default.config.noon`)
45 | } else {
46 | throw new Error('Package dir not found, set NODE_PATH per documentation.')
47 | }
48 | }
49 | obj.dmuse.date.stamp = new Date().toJSON()
50 | obj.onelook.date.stamp = new Date().toJSON()
51 | obj.rbrain.date.stamp = new Date().toJSON()
52 | obj.wordnik.date.stamp = new Date().toJSON()
53 | let fileExists = null
54 | try {
55 | fs.statSync(CFILE)
56 | fileExists = true
57 | } catch (e) {
58 | if (e.code === 'ENOENT') {
59 | fileExists = false
60 | }
61 | }
62 | if (fileExists) {
63 | if (argv.f) {
64 | const config = noon.load(CFILE)
65 | obj.dmuse.date.stamp = config.dmuse.date.stamp
66 | obj.dmuse.date.remain = config.dmuse.date.remain
67 | obj.onelook.date.stamp = config.onelook.date.stamp
68 | obj.onelook.date.remain = config.onelook.date.remain
69 | obj.rbrain.date.stamp = config.rbrain.date.stamp
70 | obj.rbrain.date.remain = config.rbrain.date.remain
71 | obj.wordnik.date.stamp = config.wordnik.date.stamp
72 | obj.wordnik.date.remain = config.wordnik.date.remain
73 | noon.save(CFILE, obj)
74 | console.log(`Overwrote ${chalk.white.bold(CFILE)}.`)
75 | } else {
76 | console.log(`Using configuration at ${chalk.white.bold(CFILE)}.`)
77 | }
78 | } else if (!fileExists) {
79 | noon.save(CFILE, obj)
80 | console.log(`Created ${chalk.white.bold(CFILE)}.`)
81 | }
82 | const config = noon.load(CFILE)
83 | const theme = themes.loadTheme(config.theme)
84 | if (os.platform() === 'windows') themes.label(theme, 'right', 'Notice', 'Please see the README for best user experience on Windows.')
85 | if (argv.v) {
86 | themes.label(theme, 'down', 'Configuration')
87 | console.log('Your current configuration is:')
88 | console.log(noon.stringify(config, {
89 | indent: 2,
90 | align: true,
91 | maxalign: 32,
92 | sort: true,
93 | colors: true
94 | }))
95 | console.log('')
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/commands/configuration/set.js:
--------------------------------------------------------------------------------
1 | const themes = require('../../themes')
2 | const tools = require('../../tools')
3 |
4 | const chalk = require('chalk')
5 | const dot = require('dot-prop')
6 | const noon = require('noon')
7 |
8 | const CFILE = `${process.env.HOME}/.leximaven.noon`
9 |
10 | exports.command = 'set '
11 | exports.aliases = ['s']
12 | exports.desc = 'Set a config value'
13 | exports.builder = {}
14 | exports.handler = (argv) => {
15 | const key = argv.key
16 | let value = argv.value
17 | value = tools.checkBoolean(value)
18 | tools.checkConfig(CFILE)
19 | const config = noon.load(CFILE)
20 | const theme = themes.loadTheme(config.theme)
21 | if (config.verbose) themes.label(theme, 'down', 'Configuration')
22 | if (dot.has(config, key)) {
23 | if (/\./i.test(key)) {
24 | if (/^\w*\.date/i.test(key)) {
25 | throw new Error("API limits hardcoded, can't set this key.")
26 | } else {
27 | dot.set(config, key, value)
28 | }
29 | } else {
30 | config[key] = value
31 | }
32 | } else {
33 | throw new Error(`Option ${key} not found.`)
34 | }
35 | noon.save(CFILE, config)
36 | console.log(`Set option ${chalk.white.bold(key)} to ${chalk.white.bold(value)}.`)
37 | }
38 |
--------------------------------------------------------------------------------
/src/commands/datamuse.js:
--------------------------------------------------------------------------------
1 | /* eslint no-unused-vars: 0 */
2 | exports.command = 'datamuse '
3 | exports.aliases = ['dmuse', 'dm']
4 | exports.desc = 'Datamuse tasks'
5 | exports.builder = (yargs) => yargs.commandDir('datamuse')
6 | exports.handler = (argv) => {}
7 |
--------------------------------------------------------------------------------
/src/commands/datamuse/get.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const chalk = require('chalk')
8 | const http = require('good-guy-http')()
9 | const noon = require('noon')
10 | const ora = require('ora')
11 |
12 | const CFILE = `${process.env.HOME}/.leximaven.noon`
13 |
14 | exports.command = 'get '
15 | exports.desc = 'Datamuse query'
16 | exports.builder = {
17 | out: {
18 | alias: 'o',
19 | desc: 'Write cson, json, noon, plist, yaml, xml',
20 | default: '',
21 | type: 'string'
22 | },
23 | force: {
24 | alias: 'f',
25 | desc: 'Force overwriting outfile',
26 | default: false,
27 | type: 'boolean'
28 | },
29 | save: {
30 | alias: 's',
31 | desc: 'Save flags to config file',
32 | default: false,
33 | type: 'boolean'
34 | },
35 | max: {
36 | alias: 'm',
37 | desc: 'Maximum number of results, 1 to 1000',
38 | default: 5,
39 | type: 'number'
40 | }
41 | }
42 | exports.handler = (argv) => {
43 | tools.checkConfig(CFILE)
44 | let config = noon.load(CFILE)
45 | let proceed = false
46 | let reset = false
47 | const stamp = new Date(config.dmuse.date.stamp)
48 | const hours = df.differenceInHours(new Date(), stamp)
49 | const minutes = df.differenceInMinutes(new Date(), stamp)
50 | const checkStamp = tools.limitDmuse(config)
51 | config = checkStamp[0]
52 | proceed = checkStamp[1]
53 | reset = checkStamp[2]
54 | if (proceed) {
55 | const userConfig = {
56 | dmuse: {
57 | max: argv.m
58 | }
59 | }
60 | if (config.merge) config = _.merge({}, config, userConfig)
61 | if (argv.s && config.merge) noon.save(CFILE, config)
62 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
63 | const theme = themes.loadTheme(config.theme)
64 | if (config.verbose) themes.label(theme, 'down', 'Datamuse')
65 | const ccont = []
66 | ccont.push(argv.condition)
67 | if (argv._.length > 1) {
68 | for (let i = 0; i <= argv._.length - 1; i++) {
69 | if (argv._[i] !== 'datamuse' && argv._[i] !== 'dmuse' && argv._[i] !== 'dm' && argv._[i] !== 'get') {
70 | ccont.push(argv._[i])
71 | }
72 | }
73 | }
74 | const prefix = 'http://api.datamuse.com/words?'
75 | let conditions = `max=${config.dmuse.max}&`
76 | for (let i = 0; i <= ccont.length - 1; i++) { conditions = `${conditions}&${ccont[i]}` }
77 | let url = `${prefix}${conditions}`
78 | url = encodeURI(url)
79 | const tags = {
80 | n: 'noun',
81 | adj: 'adjective',
82 | adv: 'adverb',
83 | syn: 'synonym'
84 | }
85 | const tofile = {
86 | type: 'datamuse',
87 | source: 'http://datamuse.com/api',
88 | url
89 | }
90 | const ctstyle = _.get(chalk, theme.content.style)
91 | const spinner = ora({
92 | text: `${chalk.bold.cyan('Loading results...')}`,
93 | spinner: 'dots8',
94 | color: 'yellow'
95 | })
96 | http({ url }, (error, response) => {
97 | if (!error && response.statusCode === 200) {
98 | if (response.headers['x-gg-state'] === 'cached') {
99 | config.dmuse.date.remain++
100 | noon.save(CFILE, config)
101 | if (config.usage) console.log('Cached response, not decrementing usage.')
102 | }
103 | const resp = JSON.parse(response.body)
104 | spinner.stop()
105 | spinner.clear()
106 | for (let i = 0; i <= resp.length - 1; i++) {
107 | const item = resp[i]
108 | themes.label(theme, 'right', 'Match', `${item.word} `)
109 | tofile[[`match${i}`]] = item.word
110 | if (item.tags !== undefined && item.tags !== []) {
111 | themes.label(theme, 'right', 'Tag')
112 | for (let j = 0; j <= item.tags.length - 1; j++) {
113 | if (j === item.tags.length - 1) {
114 | process.stdout.write(ctstyle(`${tags[item.tags[j]]}`))
115 | tofile[[`tags${j}`]] = tags[item.tags[j]]
116 | } else process.stdout.write(ctstyle(`${tags[item.tags[j]]}, `))
117 | }
118 | console.log('')
119 | }
120 | }
121 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
122 | if (config.usage) reset ? console.log(`Timestamp expired, reset usage limits.\n${config.dmuse.date.remain}/${config.dmuse.date.limit} requests remaining today.`) : console.log(`${config.dmuse.date.remain}/${config.dmuse.date.limit} requests remaining today, will reset in ${23 - hours} hours, ${59 - minutes} minutes.`)
123 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
124 | })
125 | } else throw new Error(`Reached today's usage limit of ${config.dmuse.date.limit}.`)
126 | }
127 |
--------------------------------------------------------------------------------
/src/commands/datamuse/info.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0, no-unused-vars:0 */
2 | const tools = require('../../tools')
3 |
4 | const chalk = require('chalk')
5 | const df = require('date-fns')
6 | const http = require('good-guy-http')()
7 | const noon = require('noon')
8 |
9 | const CFILE = `${process.env.HOME}/.leximaven.noon`
10 |
11 | exports.command = 'info'
12 | exports.desc = 'Datamuse metrics'
13 | exports.builder = {}
14 | exports.handler = (argv) => {
15 | tools.checkConfig(CFILE)
16 | const config = noon.load(CFILE)
17 | const url = 'http://api.datamuse.com/metrics'
18 | http({ url }, (error, response) => {
19 | if (!error && response.statusCode === 200) {
20 | const body = JSON.parse(response.body)
21 | const version = body[0]
22 | const qps = body[1]
23 | const sugf = body[2]
24 | const sugn = body[3]
25 | const wordf = body[4]
26 | const wordn = body[5]
27 | console.log(chalk.white(`Current queries per second (v${Math.round(version.value * 100) / 100.0}): ${Math.round(qps.value * 100) / 100.0}`))
28 | console.log(chalk.white(`Latency (/words): ${Math.round(wordf.value * 100000) / 100.0} ms (median), ${Math.round(wordn.value * 100000) / 100.0} ms (99 %ile)`))
29 | console.log(chalk.white(`Latency (/sug): ${Math.round(sugf.value * 100000) / 100.0} ms (median), ${Math.round(sugn.value * 100000) / 100.0} ms (99 %ile)`))
30 | } else {
31 | throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
32 | }
33 | })
34 | const limit = config.dmuse.date.limit
35 | const remain = config.dmuse.date.remain
36 | const stamp = new Date(config.dmuse.date.stamp)
37 | const hours = df.differenceInHours(new Date(), stamp)
38 | const minutes = df.differenceInMinutes(new Date(), stamp)
39 | console.log(chalk.white(`${remain}/${limit} requests remain today, will reset in ${23 - hours} hours, ${59 - minutes} minutes.`))
40 | }
41 |
--------------------------------------------------------------------------------
/src/commands/list.js:
--------------------------------------------------------------------------------
1 | /* eslint no-unused-vars: 0 */
2 | const themes = require('../themes')
3 |
4 | exports.command = 'list'
5 | exports.aliases = ['ls', 'themes']
6 | exports.desc = 'Get a list of installed themes'
7 | exports.builder = {}
8 | exports.handler = (argv) => {
9 | const list = themes.getThemes()
10 | for (let i = 0; i <= list.length - 1; i++) {
11 | const currentTheme = themes.loadTheme(list[i])
12 | const sample = 'Morbi ornare pulvinar metus, non faucibus arcu ultricies non.'
13 | themes.label(currentTheme, 'down', list[i], sample)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/commands/onelook.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../themes')
3 | const tools = require('../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const chalk = require('chalk')
8 | const http = require('good-guy-http')()
9 | const noon = require('noon')
10 | const xml2js = require('xml2js')
11 |
12 | const CFILE = `${process.env.HOME}/.leximaven.noon`
13 |
14 | exports.command = 'onelook '
15 | exports.aliases = ['one', 'ol']
16 | exports.desc = 'Onelook definitions'
17 | exports.builder = {
18 | out: {
19 | alias: 'o',
20 | desc: 'Write cson, json, noon, plist, yaml, xml',
21 | default: '',
22 | type: 'string'
23 | },
24 | force: {
25 | alias: 'f',
26 | desc: 'Force overwriting outfile',
27 | default: false,
28 | type: 'boolean'
29 | },
30 | save: {
31 | alias: 's',
32 | desc: 'Save flags to config file',
33 | default: false,
34 | type: 'boolean'
35 | },
36 | links: {
37 | alias: 'l',
38 | desc: 'Include resource links',
39 | default: false,
40 | type: 'boolean'
41 | }
42 | }
43 | exports.handler = (argv) => {
44 | tools.checkConfig(CFILE)
45 | let config = noon.load(CFILE)
46 | let proceed = false
47 | let reset = false
48 | const checkStamp = tools.limitOnelook(config)
49 | config = checkStamp[0]
50 | proceed = checkStamp[1]
51 | reset = checkStamp[2]
52 | const stamp = new Date(config.onelook.date.stamp)
53 | const hours = df.differenceInHours(new Date(), stamp)
54 | const minutes = df.differenceInMinutes(new Date(), stamp)
55 | if (proceed) {
56 | const userConfig = {
57 | onelook: {
58 | links: argv.l
59 | }
60 | }
61 | if (config.merge) config = _.merge({}, config, userConfig)
62 | if (argv.s && config.merge) noon.save(CFILE, config)
63 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
64 | const theme = themes.loadTheme(config.theme)
65 | if (config.verbose) themes.label(theme, 'down', 'Onelook')
66 | const acont = []
67 | acont.push(argv.word)
68 | if (argv._.length > 1) {
69 | for (let i = 0; i <= argv._.length - 1; i++) {
70 | if (argv._[i] !== 'onelook' && argv._[i] !== 'one' && argv._[i] !== 'ol') acont.push(argv._[i])
71 | }
72 | }
73 | let url = `http://onelook.com/?xml=1&w=${acont.join('+')}`
74 | url = encodeURI(url)
75 | const tofile = {
76 | type: 'onelook',
77 | source: 'http://www.onelook.com',
78 | url
79 | }
80 | const ctstyle = _.get(chalk, theme.content.style)
81 | http({ url }, (error, response) => {
82 | if (!error && response.statusCode === 200) {
83 | if (response.headers['x-gg-state'] === 'cached') {
84 | config.onelook.date.remain++
85 | noon.save(CFILE, config)
86 | if (config.usage) console.log('Cached response, not decrementing usage.')
87 | }
88 | const body = response.body
89 | const parser = new xml2js.Parser()
90 | parser.parseString(body, (err, result) => {
91 | if (!err) {
92 | const resp = result.OLResponse
93 | const phrase = resp.OLPhrases[0]
94 | const similar = resp.OLSimilar[0]
95 | const quickdef = resp.OLQuickDef
96 | const resources = resp.OLRes
97 | themes.label(theme, 'down', 'Definition')
98 | if (Array.isArray(quickdef) && quickdef.length > 1) {
99 | for (let i = 0; i <= quickdef.length - 1; i++) {
100 | let item = quickdef[i]
101 | item = item.replace(/<|>|\n|\/i/g, '')
102 | item = item.replace(/i"/g, '"')
103 | console.log(ctstyle(item))
104 | tofile[[`definition${i}`]] = item
105 | }
106 | } else {
107 | const definition = quickdef[0].replace(/<|>|\n|\/i/g, '')
108 | console.log(ctstyle(definition))
109 | tofile.definition = definition
110 | }
111 | if (phrase) {
112 | const phrases = phrase.replace(/\n/g, '')
113 | themes.label(theme, 'down', 'Phrases', phrases)
114 | tofile.phrase = phrases
115 | }
116 | if (similar) {
117 | const sim = similar.replace(/\n/g, '')
118 | themes.label(theme, 'down', 'Similar', sim)
119 | tofile.sim = sim
120 | }
121 | if (config.onelook.links) {
122 | themes.label(theme, 'down', 'Resources')
123 | for (let i = 0; i <= resources.length - 1; i++) {
124 | const item = resources[i]
125 | const res = tools.arrToStr(item.OLResName).replace(/\n/g, '')
126 | const link = tools.arrToStr(item.OLResLink).replace(/\n/g, '')
127 | const home = tools.arrToStr(item.OLResHomeLink).replace(/\n/g, '')
128 | themes.label(theme, 'right', res, link)
129 | tofile[[`res${i}`]] = res
130 | tofile[[`link${i}`]] = link
131 | tofile[[`home${i}`]] = home
132 | }
133 | }
134 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
135 | if (config.usage) {
136 | if (reset) {
137 | console.log('Timestamp expired, reset usage limits.')
138 | console.log(`${config.onelook.date.remain}/${config.onelook.date.limit} requests remaining today.`)
139 | } else console.log(`${config.onelook.date.remain}/${config.onelook.date.limit} requests remaining today, will reset in ${23 - hours} hours, ${59 - minutes} minutes.`)
140 | }
141 | } else {
142 | throw new Error(err)
143 | }
144 | })
145 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
146 | })
147 | } else throw new Error(`Reached today's usage limit of ${config.onelook.date.limit}.`)
148 | }
149 |
--------------------------------------------------------------------------------
/src/commands/random.js:
--------------------------------------------------------------------------------
1 | const rand = require('random-word')
2 |
3 | exports.command = 'random'
4 | exports.aliases = ['rand', 'rw']
5 | exports.desc = 'Get a random word'
6 | exports.builder = {}
7 | exports.handler = (argv) => {
8 | console.log(rand())
9 | }
10 |
--------------------------------------------------------------------------------
/src/commands/rhymebrain.js:
--------------------------------------------------------------------------------
1 | /* eslint no-unused-vars: 0 */
2 | exports.command = 'rhymebrain '
3 | exports.aliases = ['rbrain', 'rb']
4 | exports.desc = 'Rhymebrain operations'
5 | exports.builder = (yargs) => yargs.commandDir('rhymebrain')
6 | exports.handler = (argv) => {}
7 |
--------------------------------------------------------------------------------
/src/commands/rhymebrain/combine.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const http = require('good-guy-http')()
8 | const noon = require('noon')
9 |
10 | const CFILE = `${process.env.HOME}/.leximaven.noon`
11 |
12 | exports.command = 'combine '
13 | exports.aliases = ['comb', 'portmanteau']
14 | exports.desc = 'Rhymebrain portmanteaus'
15 | exports.builder = {
16 | out: {
17 | alias: 'o',
18 | desc: 'Write cson, json, noon, plist, yaml, xml',
19 | default: '',
20 | type: 'string'
21 | },
22 | force: {
23 | alias: 'f',
24 | desc: 'Force overwriting outfile',
25 | default: false,
26 | type: 'boolean'
27 | },
28 | save: {
29 | alias: 's',
30 | desc: 'Save flags to config file',
31 | default: false,
32 | type: 'boolean'
33 | },
34 | lang: {
35 | alias: 'l',
36 | desc: 'ISO 639-1 language code',
37 | default: 'en',
38 | type: 'string'
39 | },
40 | max: {
41 | alias: 'm',
42 | desc: 'Max results to return',
43 | default: 5,
44 | type: 'number'
45 | }
46 | }
47 | exports.handler = (argv) => {
48 | tools.checkConfig(CFILE)
49 | let config = noon.load(CFILE)
50 | let proceed = false
51 | let reset = false
52 | const stamp = new Date(config.rbrain.date.stamp)
53 | const minutes = df.differenceInMinutes(new Date(), stamp)
54 | const checkStamp = tools.limitRbrain(config)
55 | config = checkStamp[0]
56 | proceed = checkStamp[1]
57 | reset = checkStamp[2]
58 | if (proceed) {
59 | const userConfig = {
60 | rbrain: {
61 | combine: {
62 | lang: argv.l,
63 | max: argv.m
64 | }
65 | }
66 | }
67 | if (config.merge) config = _.merge({}, config, userConfig)
68 | if (argv.s && config.merge) noon.save(CFILE, config)
69 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
70 | const theme = themes.loadTheme(config.theme)
71 | if (config.verbose) themes.label(theme, 'down', 'Rhymebrain')
72 | const query = argv.query
73 | const task = 'Portmanteaus'
74 | const prefix = 'http://rhymebrain.com/talk?function=get'
75 | const uri = `${prefix}${task}&word=${query}&`
76 | const pcont = []
77 | pcont.push(`lang=${config.rbrain.combine.lang}&`)
78 | pcont.push(`maxResults=${config.rbrain.combine.max}&`)
79 | const rest = pcont.join('')
80 | let url = `${uri}${rest}`
81 | url = encodeURI(url)
82 | themes.label(theme, 'down', task)
83 | const tofile = {
84 | type: 'portmanteau',
85 | source: 'http://rhymebrain.com',
86 | url
87 | }
88 | http({ url }, (error, response) => {
89 | if (!error && response.statusCode === 200) {
90 | if (response.headers['x-gg-state'] === 'cached') {
91 | config.rbrain.date.remain++
92 | noon.save(CFILE, config)
93 | if (config.usage) console.log('Cached response, not decrementing usage.')
94 | }
95 | const list = JSON.parse(response.body)
96 | for (let i = 0; i <= list.length - 1; i++) {
97 | const item = list[i]
98 | themes.label(theme, 'right', item.source, item.combined)
99 | tofile[[`set${i}`]] = item.source
100 | tofile[[`portmanteau${i}`]] = item.combined
101 | }
102 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
103 | if (config.usage) reset ? console.log(`Timestamp expired, reset usage limits.\n${config.rbrain.date.remain}/${config.rbrain.date.limit} requests remaining this hour.`) : console.log(`${config.rbrain.date.remain}/${config.rbrain.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
104 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
105 | })
106 | } else throw new Error(`Reached this hour's usage limit of ${config.rbrain.date.limit}.`)
107 | }
108 |
--------------------------------------------------------------------------------
/src/commands/rhymebrain/info.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const chalk = require('chalk')
7 | const df = require('date-fns')
8 | const http = require('good-guy-http')()
9 | const noon = require('noon')
10 |
11 | const CFILE = `${process.env.HOME}/.leximaven.noon`
12 |
13 | exports.command = 'info '
14 | exports.desc = 'Rhymebrain word info'
15 | exports.builder = {
16 | out: {
17 | alias: 'o',
18 | desc: 'Write cson, json, noon, plist, yaml, xml',
19 | default: '',
20 | type: 'string'
21 | },
22 | force: {
23 | alias: 'f',
24 | desc: 'Force overwriting outfile',
25 | default: false,
26 | type: 'boolean'
27 | },
28 | save: {
29 | alias: 's',
30 | desc: 'Save flags to config file',
31 | default: false,
32 | type: 'boolean'
33 | },
34 | lang: {
35 | alias: 'l',
36 | desc: 'ISO 639-1 language code',
37 | default: 'en',
38 | type: 'string'
39 | }
40 | }
41 | exports.handler = (argv) => {
42 | tools.checkConfig(CFILE)
43 | let config = noon.load(CFILE)
44 | let proceed = false
45 | let reset = false
46 | const stamp = new Date(config.rbrain.date.stamp)
47 | const minutes = df.differenceInMinutes(new Date(), stamp)
48 | const checkStamp = tools.limitRbrain(config)
49 | config = checkStamp[0]
50 | proceed = checkStamp[1]
51 | reset = checkStamp[2]
52 | if (proceed) {
53 | const userConfig = {
54 | rbrain: {
55 | info: {
56 | lang: argv.l
57 | }
58 | }
59 | }
60 | if (config.merge) config = _.merge({}, config, userConfig)
61 | if (argv.s && config.merge) noon.save(CFILE, config)
62 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
63 | const theme = themes.loadTheme(config.theme)
64 | if (config.verbose) themes.label(theme, 'down', 'Rhymebrain')
65 | const word = argv.word
66 | const task = 'WordInfo'
67 | const prefix = 'http://rhymebrain.com/talk?function=get'
68 | const uri = `${prefix}${task}&word=${word}&lang=${config.rbrain.info.lang}`
69 | const url = encodeURI(uri)
70 | themes.label(theme, 'down', 'Word Info')
71 | const tofile = {
72 | type: 'word info',
73 | source: 'http://rhymebrain.com',
74 | url
75 | }
76 | const ctstyle = _.get(chalk, theme.content.style)
77 | http({ url }, (error, response) => {
78 | if (!error && response.statusCode === 200) {
79 | if (response.headers['x-gg-state'] === 'cached') {
80 | config.rbrain.date.remain++
81 | noon.save(CFILE, config)
82 | if (config.usage) console.log('Cached response, not decrementing usage.')
83 | }
84 | const info = JSON.parse(response.body)
85 | themes.label(theme, 'right', 'Arpabet', info.pron)
86 | themes.label(theme, 'right', 'IPA', info.ipa)
87 | themes.label(theme, 'right', 'Syllables', info.syllables)
88 | tofile.arpabet = info.pron
89 | tofile.ipa = info.ipa
90 | tofile.syllables = info.syllables
91 | const flags = []
92 | if (info.flags.match(/a/)) {
93 | flags.push(ctstyle(`[${chalk.red.bold('Offensive')}]`))
94 | tofile.offensive = true
95 | }
96 | if (info.flags.match(/b/)) {
97 | flags.push(ctstyle('[Found in dictionary]'))
98 | tofile.dict = true
99 | }
100 | if (info.flags.match(/c/)) {
101 | flags.push(ctstyle('[Trusted pronunciation, not generated]'))
102 | tofile.trusted = true
103 | }
104 | themes.label(theme, 'right', 'Word Flags', flags.join(''))
105 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
106 | reset ? console.log(`Timestamp expired, reset usage limits.\n${config.rbrain.date.remain}/${config.rbrain.date.limit} requests remaining this hour.`) : console.log(`${config.rbrain.date.remain}/${config.rbrain.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
107 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
108 | })
109 | } else throw new Error(`Reached this hour's usage limit of ${config.rbrain.date.limit}.`)
110 | }
111 |
--------------------------------------------------------------------------------
/src/commands/rhymebrain/rhyme.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const chalk = require('chalk')
7 | const df = require('date-fns')
8 | const http = require('good-guy-http')()
9 | const noon = require('noon')
10 |
11 | const CFILE = `${process.env.HOME}/.leximaven.noon`
12 |
13 | exports.command = 'rhyme '
14 | exports.aliases = ['rh']
15 | exports.desc = 'Rhymebrain rhymes'
16 | exports.builder = {
17 | out: {
18 | alias: 'o',
19 | desc: 'Write cson, json, noon, plist, yaml, xml',
20 | default: '',
21 | type: 'string'
22 | },
23 | force: {
24 | alias: 'f',
25 | desc: 'Force overwriting outfile',
26 | default: false,
27 | type: 'boolean'
28 | },
29 | save: {
30 | alias: 's',
31 | desc: 'Save flags to config file',
32 | default: false,
33 | type: 'boolean'
34 | },
35 | lang: {
36 | alias: 'l',
37 | desc: 'ISO 639-1 language code',
38 | default: 'en',
39 | type: 'string'
40 | },
41 | max: {
42 | alias: 'm',
43 | desc: 'Max results to return',
44 | default: 5,
45 | type: 'number'
46 | }
47 | }
48 | exports.handler = (argv) => {
49 | tools.checkConfig(CFILE)
50 | let config = noon.load(CFILE)
51 | let proceed = false
52 | let reset = false
53 | const stamp = new Date(config.rbrain.date.stamp)
54 | const minutes = df.differenceInMinutes(new Date(), stamp)
55 | const checkStamp = tools.limitRbrain(config)
56 | config = checkStamp[0]
57 | proceed = checkStamp[1]
58 | reset = checkStamp[2]
59 | if (proceed) {
60 | const userConfig = {
61 | rbrain: {
62 | rhyme: {
63 | lang: argv.l,
64 | max: argv.m
65 | }
66 | }
67 | }
68 | if (config.merge) config = _.merge({}, config, userConfig)
69 | if (argv.s && config.merge) noon.save(CFILE, config)
70 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
71 | const theme = themes.loadTheme(config.theme)
72 | if (config.verbose) themes.label(theme, 'down', 'Rhymebrain')
73 | const word = argv.word
74 | const task = 'Rhymes'
75 | const prefix = 'http://rhymebrain.com/talk?function=get'
76 | const uri = `${prefix}${task}&word=${word}&`
77 | const pcont = []
78 | pcont.push(`lang=${config.rbrain.rhyme.lang}&`)
79 | pcont.push(`maxResults=${config.rbrain.rhyme.max}&`)
80 | const rest = pcont.join('')
81 | let url = `${uri}${rest}`
82 | url = encodeURI(url)
83 | const tofile = {
84 | type: 'rhyme',
85 | source: 'http://rhymebrain.com',
86 | url
87 | }
88 | const ctstyle = _.get(chalk, theme.content.style)
89 | http({ url }, (error, response) => {
90 | if (!error && response.statusCode === 200) {
91 | if (response.headers['x-gg-state'] === 'cached') {
92 | config.rbrain.date.remain++
93 | noon.save(CFILE, config)
94 | if (config.usage) console.log('Cached response, not decrementing usage.')
95 | }
96 | const list = JSON.parse(response.body)
97 | const lcont = []
98 | for (let i = 0; i <= list.length - 1; i++) {
99 | lcont.push(list[i].word)
100 | }
101 | lcont.sort((a, b) => {
102 | if (a < b) return -1
103 | if (a > b) return 1
104 | return 0
105 | })
106 | const rcont = []
107 | for (let j = 0; j <= lcont.length - 1; j++) {
108 | const item = lcont[j]
109 | rcont.push(ctstyle(item))
110 | item.score >= 300 ? tofile[[`hiscore${j}`]] = item : tofile[[`rhyme${j}`]] = item
111 | }
112 | rcont.sort()
113 | themes.label(theme, 'right', task, rcont.join(', '))
114 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
115 | if (config.usage) reset ? console.log(`Timestamp expired, reset usage limits.\n${config.rbrain.date.remain}/${config.rbrain.date.limit} requests remaining this hour.`) : console.log(`${config.rbrain.date.remain}/${config.rbrain.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
116 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
117 | })
118 | } else throw new Error(`Reached this hour's usage limit of ${config.rbrain.date.limit}.`)
119 | }
120 |
--------------------------------------------------------------------------------
/src/commands/urban.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../themes')
3 | const tools = require('../tools')
4 |
5 | const _ = require('lodash')
6 | const http = require('good-guy-http')()
7 | const noon = require('noon')
8 |
9 | const CFILE = `${process.env.HOME}/.leximaven.noon`
10 |
11 | exports.command = 'urban '
12 | exports.aliases = ['urb', 'slang']
13 | exports.desc = 'Urban Dictionary definitions'
14 | exports.builder = {
15 | out: {
16 | alias: 'o',
17 | desc: 'Write cson, json, noon, plist, yaml, xml',
18 | default: '',
19 | type: 'string'
20 | },
21 | force: {
22 | alias: 'f',
23 | desc: 'Force overwriting outfile',
24 | default: false,
25 | type: 'boolean'
26 | },
27 | save: {
28 | alias: 's',
29 | desc: 'Save flags to config file',
30 | default: false,
31 | type: 'boolean'
32 | },
33 | limit: {
34 | alias: 'l',
35 | desc: 'Limit number of results',
36 | default: 5,
37 | type: 'number'
38 | }
39 | }
40 | exports.handler = (argv) => {
41 | tools.checkConfig(CFILE)
42 | let config = noon.load(CFILE)
43 | const userConfig = {
44 | urban: {
45 | limit: argv.l
46 | }
47 | }
48 | if (config.merge) config = _.merge({}, config, userConfig)
49 | if (argv.s && config.merge) noon.save(CFILE, config)
50 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
51 | const theme = themes.loadTheme(config.theme)
52 | if (config.verbose) themes.label(theme, 'down', 'Urban Dictionary')
53 | const ucont = []
54 | ucont.push(argv.query)
55 | if (argv._.length > 1) {
56 | for (let i = 0; i <= argv._.length - 1; i++) {
57 | if (argv._[i] !== 'urban' && argv._[i] !== 'urb' && argv._[i] !== 'slang') ucont.push(argv._[i])
58 | }
59 | }
60 | let words = ''
61 | if (ucont.length > 1) {
62 | words = ucont.join('+')
63 | } else {
64 | words = ucont[0]
65 | }
66 | let url = `http://api.urbandictionary.com/v0/define?term=${words}`
67 | url = encodeURI(url)
68 | const tofile = {
69 | type: 'urban',
70 | source: 'http://www.urbandictionary.com',
71 | url
72 | }
73 | http({ url }, (error, response) => {
74 | if (!error && response.statusCode === 200) {
75 | const body = JSON.parse(response.body)
76 | const limit = config.urban.limit
77 | const list = body.list.slice(0, limit)
78 | for (let i = 0; i <= list.length - 1; i++) {
79 | const result = list[i]
80 | themes.label(theme, 'down', 'Definition', result.definition)
81 | tofile[[`definition${i}`]] = result.definition
82 | }
83 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
84 | } else {
85 | throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
86 | }
87 | })
88 | }
89 |
--------------------------------------------------------------------------------
/src/commands/wordmap.js:
--------------------------------------------------------------------------------
1 | const themes = require('../themes')
2 | const tools = require('../tools')
3 |
4 | const _ = require('lodash')
5 | const child = require('child_process')
6 | const fs = require('fs')
7 | const noon = require('noon')
8 |
9 | const CFILE = `${process.env.HOME}/.leximaven.noon`
10 |
11 | exports.command = 'wordmap '
12 | exports.aliases = ['map', 'wm']
13 | exports.desc = 'Maps of word info'
14 | exports.builder = {
15 | limit: {
16 | alias: 'l',
17 | desc: 'Limits the number of results',
18 | default: 1,
19 | type: 'number'
20 | },
21 | save: {
22 | alias: 's',
23 | desc: 'Save flags to config file',
24 | default: false,
25 | type: 'boolean'
26 | }
27 | }
28 | exports.handler = (argv) => {
29 | tools.checkConfig(CFILE)
30 | let config = noon.load(CFILE)
31 | const userConfig = {
32 | wordmap: {
33 | limit: argv.l
34 | }
35 | }
36 | if (config.merge) config = _.merge({}, config, userConfig)
37 | if (argv.s && config.merge) noon.save(CFILE, config)
38 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
39 | const theme = themes.loadTheme(config.theme)
40 | if (config.verbose) themes.label(theme, 'down', 'Wordmap')
41 | const word = argv.word
42 | const l = argv.l
43 | let bin = ''
44 | let dirExists = null
45 | try {
46 | fs.statSync('bin/leximaven.js')
47 | dirExists = true
48 | } catch (e) {
49 | if (e.code === 'ENOENT') dirExists = false
50 | }
51 | dirExists ? bin = 'bin/leximaven.js' : bin = `${process.env.NODE_PATH}/leximaven/bin/leximaven.js`
52 | child.spawnSync('node', [bin, 'rbrain', 'combine', `-m${l}`, `${word}`], { stdio: 'inherit' })
53 | child.spawnSync('node', [bin, 'rbrain', 'info', `${word}`], { stdio: 'inherit' })
54 | child.spawnSync('node', [bin, 'rbrain', 'rhyme', `-m${l}`, `${word}`], { stdio: 'inherit' })
55 | child.spawnSync('node', [bin, 'wordnik', 'define', `-l${l}`, `${word}`], { stdio: 'inherit' })
56 | child.spawnSync('node', [bin, 'wordnik', 'example', `-l${l}`, `${word}`], { stdio: 'inherit' })
57 | child.spawnSync('node', [bin, 'wordnik', 'hyphen', `${word}`], { stdio: 'inherit' })
58 | child.spawnSync('node', [bin, 'wordnik', 'origin', `${word}`], { stdio: 'inherit' })
59 | child.spawnSync('node', [bin, 'wordnik', 'phrase', `-l${l}`, `${word}`], { stdio: 'inherit' })
60 | child.spawnSync('node', [bin, 'wordnik', 'pronounce', `-l${l}`, `${word}`], { stdio: 'inherit' })
61 | child.spawnSync('node', [bin, 'wordnik', 'relate', `-l${l}`, `${word}`], { stdio: 'inherit' })
62 | child.spawnSync('node', [bin, 'acronym', `${word}`], { stdio: 'inherit' })
63 | child.spawnSync('node', [bin, 'dmuse', `-m${l}`, `ml=${word}`], { stdio: 'inherit' })
64 | child.spawnSync('node', [bin, 'onelook', `${word}`], { stdio: 'inherit' })
65 | child.spawnSync('node', [bin, 'urban', `-l${l}`, `${word}`], { stdio: 'inherit' })
66 | // child.spawnSync('node', [bin, 'anagram', `-t${l}`, `${word}`], { stdio: 'inherit' })
67 | }
68 |
--------------------------------------------------------------------------------
/src/commands/wordnik.js:
--------------------------------------------------------------------------------
1 | /* eslint no-unused-vars: 0 */
2 | exports.command = 'wordnik '
3 | exports.aliases = ['wnik', 'wn']
4 | exports.desc = 'Wordnik tasks'
5 | exports.builder = (yargs) => yargs.commandDir('wordnik')
6 | exports.handler = (argv) => {}
7 |
--------------------------------------------------------------------------------
/src/commands/wordnik/define.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const chalk = require('chalk')
8 | const http = require('good-guy-http')()
9 | const noon = require('noon')
10 |
11 | const CFILE = `${process.env.HOME}/.leximaven.noon`
12 |
13 | exports.command = 'define '
14 | exports.aliases = ['def']
15 | exports.desc = 'Wordnik definitions'
16 | exports.builder = {
17 | out: {
18 | alias: 'o',
19 | desc: 'Write cson, json, noon, plist, yaml, xml',
20 | default: '',
21 | type: 'string'
22 | },
23 | force: {
24 | alias: 'f',
25 | desc: 'Force overwriting outfile',
26 | default: false,
27 | type: 'boolean'
28 | },
29 | save: {
30 | alias: 's',
31 | desc: 'Save flags to config file',
32 | default: false,
33 | type: 'boolean'
34 | },
35 | limit: {
36 | alias: 'l',
37 | desc: 'Limit number of results',
38 | default: 5,
39 | type: 'number'
40 | },
41 | canon: {
42 | alias: 'c',
43 | desc: 'Use canonical',
44 | default: false,
45 | type: 'boolean'
46 | },
47 | defdict: {
48 | alias: 'd',
49 | desc: "CSV list of dictionaries or 'all'",
50 | default: 'all',
51 | type: 'string'
52 | },
53 | part: {
54 | alias: 'p',
55 | desc: 'CSV list of parts of speech. See http://developer.wordnik.com/docs.html for list of parts.',
56 | default: '',
57 | type: 'string'
58 | }
59 | }
60 | exports.handler = (argv) => {
61 | if (process.env.WORDNIK === undefined) throw new Error('Put an API key in environment variable WORDNIK per documentation.')
62 | tools.checkConfig(CFILE)
63 | let config = noon.load(CFILE)
64 | let proceed = false
65 | let reset = false
66 | const stamp = new Date(config.wordnik.date.stamp)
67 | const minutes = df.differenceInMinutes(new Date(), stamp)
68 | const checkStamp = tools.limitWordnik(config)
69 | config = checkStamp[0]
70 | proceed = checkStamp[1]
71 | reset = checkStamp[2]
72 | if (proceed) {
73 | const userConfig = {
74 | wordnik: {
75 | define: {
76 | canon: argv.c,
77 | limit: argv.l,
78 | defdict: argv.d,
79 | part: argv.p
80 | }
81 | }
82 | }
83 | if (config.merge) config = _.merge({}, config, userConfig)
84 | if (argv.s && config.merge) noon.save(CFILE, config)
85 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
86 | const theme = themes.loadTheme(config.theme)
87 | if (config.verbose) themes.label(theme, 'down', 'Wordnik')
88 | const word = argv.word
89 | const task = 'definitions'
90 | const prefix = 'http://api.wordnik.com:80/v4/word.json/'
91 | const apikey = process.env.WORDNIK
92 | const uri = `${prefix}${word}/${task}?`
93 | const pcont = []
94 | pcont.push(`useCanonical=${config.wordnik.define.canon}&`)
95 | pcont.push(`sourceDictionaries=${config.wordnik.define.defdict}&`)
96 | pcont.push('includeRelated=false&')
97 | pcont.push('includeTags=false&')
98 | pcont.push(`limit=${config.wordnik.define.limit}&`)
99 | pcont.push(`partOfSpeech=${config.wordnik.define.part}&`)
100 | pcont.push(`api_key=${apikey}`)
101 | const rest = pcont.join('')
102 | let url = `${uri}${rest}`
103 | url = encodeURI(url)
104 | const tofile = {
105 | type: 'definition',
106 | source: 'http://www.wordnik.com'
107 | }
108 | const cstyle = _.get(chalk, theme.connector.style)
109 | const ctstyle = _.get(chalk, theme.content.style)
110 | const uline = _.get(chalk, `${theme.content.style}.underline`)
111 | const conn = cstyle(theme.connector.str)
112 | http({ url }, (error, response) => {
113 | if (!error && response.statusCode === 200) {
114 | if (response.headers['x-gg-state'] === 'cached') {
115 | config.wordnik.date.remain++
116 | noon.save(CFILE, config)
117 | if (config.usage) console.log('Cached response, not decrementing usage.')
118 | }
119 | const list = JSON.parse(response.body)
120 | for (let i = 0; i <= list.length - 1; i++) {
121 | const item = list[i]
122 | const icont = []
123 | icont.push(ctstyle(`${item.text} `))
124 | icont.push(uline(item.partOfSpeech))
125 | icont.push(conn)
126 | icont.push(ctstyle(item.sourceDictionary))
127 | themes.label(theme, 'right', 'Definition', icont.join(''))
128 | tofile[[`text${i}`]] = item.text
129 | tofile[[`deftype${i}`]] = item.partOfSpeech
130 | tofile[[`source${i}`]] = item.sourceDictionary
131 | }
132 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
133 | if (config.usage) reset ? console.log(`Timestamp expired, not decrementing usage.\n${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour.`) : console.log(`${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
134 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
135 | })
136 | } else throw new Error(`Reached this hour's usage limit of ${config.wordnik.date.limit}.`)
137 | }
138 |
--------------------------------------------------------------------------------
/src/commands/wordnik/example.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const http = require('good-guy-http')()
8 | const noon = require('noon')
9 |
10 | const CFILE = `${process.env.HOME}/.leximaven.noon`
11 |
12 | exports.command = 'example '
13 | exports.aliases = ['ex']
14 | exports.desc = 'Wordnik examples'
15 | exports.builder = {
16 | out: {
17 | alias: 'o',
18 | desc: 'Write cson, json, noon, plist, yaml, xml',
19 | default: '',
20 | type: 'string'
21 | },
22 | force: {
23 | alias: 'f',
24 | desc: 'Force overwriting outfile',
25 | default: false,
26 | type: 'boolean'
27 | },
28 | save: {
29 | alias: 's',
30 | desc: 'Save flags to config file',
31 | default: false,
32 | type: 'boolean'
33 | },
34 | limit: {
35 | alias: 'l',
36 | desc: 'Limit number of results',
37 | default: 5,
38 | type: 'number'
39 | },
40 | canon: {
41 | alias: 'c',
42 | desc: 'Use canonical',
43 | default: false,
44 | type: 'boolean'
45 | },
46 | skip: {
47 | alias: 'k',
48 | desc: 'Number of results to skip',
49 | default: 0,
50 | type: 'number'
51 | }
52 | }
53 | exports.handler = (argv) => {
54 | if (process.env.WORDNIK === undefined) throw new Error('Put an API key in environment variable WORDNIK per documentation.')
55 | tools.checkConfig(CFILE)
56 | let config = noon.load(CFILE)
57 | let proceed = false
58 | let reset = false
59 | const stamp = new Date(config.wordnik.date.stamp)
60 | const minutes = df.differenceInMinutes(new Date(), stamp)
61 | const checkStamp = tools.limitWordnik(config)
62 | config = checkStamp[0]
63 | proceed = checkStamp[1]
64 | reset = checkStamp[2]
65 | if (proceed) {
66 | const userConfig = {
67 | wordnik: {
68 | example: {
69 | canon: argv.c,
70 | limit: argv.l,
71 | skip: argv.k
72 | }
73 | }
74 | }
75 | if (config.merge) config = _.merge({}, config, userConfig)
76 | if (argv.s && config.merge) noon.save(CFILE, config)
77 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
78 | const theme = themes.loadTheme(config.theme)
79 | if (config.verbose) themes.label(theme, 'down', 'Wordnik')
80 | const word = argv.word
81 | const task = 'examples'
82 | const prefix = 'http://api.wordnik.com:80/v4/word.json/'
83 | const apikey = process.env.WORDNIK
84 | const uri = `${prefix}${word}/${task}?`
85 | const pcont = []
86 | pcont.push(`useCanonical=${config.wordnik.example.canon}&`)
87 | pcont.push('includeDuplicates=false&')
88 | pcont.push(`limit=${config.wordnik.example.limit}&`)
89 | !config.wordnik.example.skip ? pcont.push('skip=0&') : pcont.push(`skip=${config.wordnik.example.skip}&`)
90 | pcont.push(`api_key=${apikey}`)
91 | const rest = pcont.join('')
92 | let url = `${uri}${rest}`
93 | url = encodeURI(url)
94 | const tofile = {
95 | type: 'example',
96 | source: 'http://www.wordnik.com'
97 | }
98 | http({ url }, (error, response) => {
99 | if (!error && response.statusCode === 200) {
100 | if (response.headers['x-gg-state'] === 'cached') {
101 | config.wordnik.date.remain++
102 | noon.save(CFILE, config)
103 | if (config.usage) console.log('Cached response, not decrementing usage.')
104 | }
105 | const body = JSON.parse(response.body)
106 | const list = body.examples
107 | for (let i = 0; i <= list.length - 1; i++) {
108 | const item = list[i]
109 | themes.label(theme, 'right', 'Example', item.text)
110 | tofile[[`example${i}`]] = item.text
111 | }
112 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
113 | if (config.usage) reset ? console.log(`Timestamp expired, not decrementing usage.\n${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour.`) : console.log(`${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
114 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
115 | })
116 | } else throw new Error(`Reached this hour's usage limit of ${config.wordnik.date.limit}.`)
117 | }
118 |
--------------------------------------------------------------------------------
/src/commands/wordnik/hyphen.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const chalk = require('chalk')
7 | const df = require('date-fns')
8 | const http = require('good-guy-http')()
9 | const noon = require('noon')
10 |
11 | const CFILE = `${process.env.HOME}/.leximaven.noon`
12 |
13 | exports.command = 'hyphen '
14 | exports.aliases = ['hyphenate', 'hy']
15 | exports.desc = 'Wordnik hyphenations'
16 | exports.builder = {
17 | out: {
18 | alias: 'o',
19 | desc: 'Write cson, json, noon, plist, yaml, xml',
20 | default: '',
21 | type: 'string'
22 | },
23 | force: {
24 | alias: 'f',
25 | desc: 'Force overwriting outfile',
26 | default: false,
27 | type: 'boolean'
28 | },
29 | save: {
30 | alias: 's',
31 | desc: 'Save flags to config file',
32 | default: false,
33 | type: 'boolean'
34 | },
35 | limit: {
36 | alias: 'l',
37 | desc: 'Limit number of results',
38 | default: 5,
39 | type: 'number'
40 | },
41 | canon: {
42 | alias: 'c',
43 | desc: 'Use canonical',
44 | default: false,
45 | type: 'boolean'
46 | },
47 | dict: {
48 | alias: 'd',
49 | desc: 'Source dictionary ahd, century, wiktionary, webster, wordnet',
50 | default: 'all',
51 | type: 'string'
52 | }
53 | }
54 | exports.handler = (argv) => {
55 | if (process.env.WORDNIK === undefined) throw new Error('Put an API key in environment variable WORDNIK per documentation.')
56 | tools.checkConfig(CFILE)
57 | let config = noon.load(CFILE)
58 | let proceed = false
59 | let reset = false
60 | const stamp = new Date(config.wordnik.date.stamp)
61 | const minutes = df.differenceInMinutes(new Date(), stamp)
62 | const checkStamp = tools.limitWordnik(config)
63 | config = checkStamp[0]
64 | proceed = checkStamp[1]
65 | reset = checkStamp[2]
66 | if (proceed) {
67 | const userConfig = {
68 | wordnik: {
69 | hyphen: {
70 | canon: argv.c,
71 | dict: argv.d,
72 | limit: argv.l
73 | }
74 | }
75 | }
76 | if (config.merge) config = _.merge({}, config, userConfig)
77 | if (argv.s && config.merge) noon.save(CFILE, config)
78 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
79 | const theme = themes.loadTheme(config.theme)
80 | if (config.verbose) themes.label(theme, 'down', 'Wordnik')
81 | const word = argv.word
82 | const task = 'hyphenation'
83 | const prefix = 'http://api.wordnik.com:80/v4/word.json/'
84 | const apikey = process.env.WORDNIK
85 | const uri = `${prefix}${word}/${task}?`
86 | const pcont = []
87 | pcont.push(`useCanonical=${config.wordnik.hyphen.canon}&`)
88 | if (argv.d !== 'all') pcont.push(`sourceDictionary=${config.wordnik.hyphen.dict}&`)
89 | pcont.push(`limit=${config.wordnik.hyphen.limit}&`)
90 | pcont.push(`api_key=${apikey}`)
91 | const rest = pcont.join('')
92 | let url = `${uri}${rest}`
93 | url = encodeURI(url)
94 | const tofile = {
95 | type: 'hyphenation',
96 | source: 'http://www.wordnik.com'
97 | }
98 | const ctstyle = _.get(chalk, theme.content.style)
99 | http({ url }, (error, response) => {
100 | if (!error && response.statusCode === 200) {
101 | if (response.headers['x-gg-state'] === 'cached') {
102 | config.wordnik.date.remain++
103 | noon.save(CFILE, config)
104 | if (config.usage) console.log('Cached response, not decrementing usage.')
105 | }
106 | const list = JSON.parse(response.body)
107 | const hcont = []
108 | for (let i = 0; i <= list.length - 1; i++) {
109 | const item = list[i]
110 | if (item.type === 'stress') {
111 | hcont.push(`${chalk.red.bold(item.text)}`)
112 | tofile[[`stress${i}`]] = item.text
113 | } else if (item.type === 'secondary stress') {
114 | hcont.push(ctstyle(item.text))
115 | tofile[[`secondary${i}`]] = item.text
116 | } else {
117 | hcont.push(ctstyle(item.text))
118 | tofile[[`syllable${i}`]] = item.text
119 | }
120 | if (i < list.length - 1) hcont.push(ctstyle('-'))
121 | }
122 | themes.label(theme, 'right', 'Hyphenation', hcont.join(''))
123 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
124 | if (config.usage) reset ? console.log(`Timestamp expired, not decrementing usage.\n${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour.`) : console.log(`${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
125 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
126 | })
127 | } else throw new Error(`Reached this hour's usage limit of ${config.wordnik.date.limit}.`)
128 | }
129 |
--------------------------------------------------------------------------------
/src/commands/wordnik/origin.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const chalk = require('chalk')
7 | const df = require('date-fns')
8 | const http = require('good-guy-http')()
9 | const noon = require('noon')
10 | const xml2js = require('xml2js')
11 |
12 | const CFILE = `${process.env.HOME}/.leximaven.noon`
13 |
14 | exports.command = 'origin '
15 | exports.aliases = ['or', 'etymology']
16 | exports.desc = 'Wordnik etymologies'
17 | exports.builder = {
18 | out: {
19 | alias: 'o',
20 | desc: 'Write cson, json, noon, plist, yaml, xml',
21 | default: '',
22 | type: 'string'
23 | },
24 | force: {
25 | alias: 'f',
26 | desc: 'Force overwriting outfile',
27 | default: false,
28 | type: 'boolean'
29 | },
30 | save: {
31 | alias: 's',
32 | desc: 'Save flags to config file',
33 | default: false,
34 | type: 'boolean'
35 | },
36 | canon: {
37 | alias: 'c',
38 | desc: 'Use canonical',
39 | default: false,
40 | type: 'boolean'
41 | }
42 | }
43 | exports.handler = (argv) => {
44 | if (process.env.WORDNIK === undefined) throw new Error('Put an API key in environment variable WORDNIK per documentation.')
45 | tools.checkConfig(CFILE)
46 | let config = noon.load(CFILE)
47 | let proceed = false
48 | let reset = false
49 | const stamp = new Date(config.wordnik.date.stamp)
50 | const minutes = df.differenceInMinutes(new Date(), stamp)
51 | const checkStamp = tools.limitWordnik(config)
52 | config = checkStamp[0]
53 | proceed = checkStamp[1]
54 | reset = checkStamp[2]
55 | if (proceed) {
56 | const userConfig = {
57 | wordnik: {
58 | origin: {
59 | canon: argv.c
60 | }
61 | }
62 | }
63 | if (config.merge) config = _.merge({}, config, userConfig)
64 | if (argv.s && config.merge) noon.save(CFILE, config)
65 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
66 | const theme = themes.loadTheme(config.theme)
67 | if (config.verbose) themes.label(theme, 'down', 'Wordnik')
68 | const word = argv.word
69 | const task = 'etymologies'
70 | const prefix = 'http://api.wordnik.com:80/v4/word.json/'
71 | const apikey = process.env.WORDNIK
72 | const uri = `${prefix}${word}/${task}?`
73 | const pcont = []
74 | pcont.push(`useCanonical=${config.wordnik.origin.canon}&`)
75 | pcont.push(`api_key=${apikey}`)
76 | const rest = pcont.join('')
77 | let url = `${uri}${rest}`
78 | url = encodeURI(url)
79 | const parser = new xml2js.Parser()
80 | const tofile = {
81 | type: 'etymology',
82 | source: 'http://www.wordnik.com'
83 | }
84 | const ctstyle = _.get(chalk, theme.content.style)
85 | http({ url }, (error, response) => {
86 | if (!error && response.statusCode === 200) {
87 | if (response.headers['x-gg-state'] === 'cached') {
88 | config.wordnik.date.remain++
89 | noon.save(CFILE, config)
90 | if (config.usage) console.log('Cached response, not decrementing usage.')
91 | }
92 | const resp = JSON.parse(response.body)
93 | const origin = resp[0]
94 | parser.parseString(origin, (err, result) => {
95 | if (!err) {
96 | const root = result.ety
97 | const content = root._
98 | let ets = root.ets
99 | ets = ets.join(', ')
100 | themes.label(theme, 'right', 'Etymology', ctstyle(`${content} ${ets}`))
101 | tofile.etymology = content
102 | tofile.origin = ets
103 | } else {
104 | throw new Error(err)
105 | }
106 | })
107 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
108 | if (config.usage) reset ? console.log(`Timestamp expired, not decrementing usage.\n${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour.`) : console.log(`${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
109 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
110 | })
111 | } else throw new Error(`Reached this hour's usage limit of ${config.wordnik.date.limit}.`)
112 | }
113 |
--------------------------------------------------------------------------------
/src/commands/wordnik/phrase.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const http = require('good-guy-http')()
8 | const noon = require('noon')
9 |
10 | const CFILE = `${process.env.HOME}/.leximaven.noon`
11 |
12 | exports.command = 'phrase '
13 | exports.aliases = ['ph', 'ngram']
14 | exports.desc = 'Wordnik bi-gram phrases'
15 | exports.builder = {
16 | out: {
17 | alias: 'o',
18 | desc: 'Write cson, json, noon, plist, yaml, xml',
19 | default: '',
20 | type: 'string'
21 | },
22 | force: {
23 | alias: 'f',
24 | desc: 'Force overwriting outfile',
25 | default: false,
26 | type: 'boolean'
27 | },
28 | save: {
29 | alias: 's',
30 | desc: 'Save flags to config file',
31 | default: false,
32 | type: 'boolean'
33 | },
34 | limit: {
35 | alias: 'l',
36 | desc: 'Limit number of results',
37 | default: 5,
38 | type: 'number'
39 | },
40 | canon: {
41 | alias: 'c',
42 | desc: 'Use canonical',
43 | default: false,
44 | type: 'boolean'
45 | },
46 | weight: {
47 | alias: 'w',
48 | desc: 'Minimum weighted mutual info',
49 | default: 13,
50 | type: 'number'
51 | }
52 | }
53 | exports.handler = (argv) => {
54 | if (process.env.WORDNIK === undefined) throw new Error('Put an API key in environment variable WORDNIK per documentation.')
55 | tools.checkConfig(CFILE)
56 | let config = noon.load(CFILE)
57 | let proceed = false
58 | let reset = false
59 | const stamp = new Date(config.wordnik.date.stamp)
60 | const minutes = df.differenceInMinutes(new Date(), stamp)
61 | const checkStamp = tools.limitWordnik(config)
62 | config = checkStamp[0]
63 | proceed = checkStamp[1]
64 | reset = checkStamp[2]
65 | if (proceed) {
66 | const userConfig = {
67 | wordnik: {
68 | phrase: {
69 | canon: argv.c,
70 | limit: argv.l,
71 | weight: argv.w
72 | }
73 | }
74 | }
75 | if (config.merge) config = _.merge({}, config, userConfig)
76 | if (argv.s && config.merge) noon.save(CFILE, config)
77 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
78 | const theme = themes.loadTheme(config.theme)
79 | if (config.verbose) themes.label(theme, 'down', 'Wordnik')
80 | const word = argv.word
81 | const task = 'phrases'
82 | const prefix = 'http://api.wordnik.com:80/v4/word.json/'
83 | const apikey = process.env.WORDNIK
84 | const uri = `${prefix}${word}/${task}?`
85 | const pcont = []
86 | pcont.push(`useCanonical=${argv.c}&`)
87 | pcont.push(`limit=${argv.l}&`)
88 | pcont.push(`wlmi=${argv.w}&`)
89 | pcont.push(`api_key=${apikey}`)
90 | const rest = pcont.join('')
91 | let url = `${uri}${rest}`
92 | url = encodeURI(url)
93 | themes.label(theme, 'down', 'Bi-gram phrases')
94 | const tofile = {
95 | type: 'phrase',
96 | source: 'http://www.wordnik.com'
97 | }
98 | http({ url }, (error, response) => {
99 | if (!error && response.statusCode === 200) {
100 | if (response.headers['x-gg-state'] === 'cached') {
101 | config.wordnik.date.remain++
102 | noon.save(CFILE, config)
103 | if (config.usage) console.log('Cached response, not decrementing usage.')
104 | }
105 | const list = JSON.parse(response.body)
106 | for (let i = 0; i <= list.length - 1; i++) {
107 | const item = list[i]
108 | console.log(`${item.gram1} ${item.gram2}`)
109 | tofile[[`agram${i}`]] = item.gram1
110 | tofile[[`bgram${i}`]] = item.gram2
111 | }
112 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
113 | if (config.usage) reset ? console.log(`Timestamp expired, not decrementing usage.\n${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour.`) : console.log(`${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
114 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
115 | })
116 | } else throw new Error(`Reached this hour's usage limit of ${config.wordnik.date.limit}.`)
117 | }
118 |
--------------------------------------------------------------------------------
/src/commands/wordnik/pronounce.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const http = require('good-guy-http')()
8 | const noon = require('noon')
9 |
10 | const CFILE = `${process.env.HOME}/.leximaven.noon`
11 |
12 | exports.command = 'pronounce '
13 | exports.aliases = ['pr']
14 | exports.desc = 'Wordnik pronunciations'
15 | exports.builder = {
16 | out: {
17 | alias: 'o',
18 | desc: 'Write cson, json, noon, plist, yaml, xml',
19 | default: '',
20 | type: 'string'
21 | },
22 | force: {
23 | alias: 'f',
24 | desc: 'Force overwriting outfile',
25 | default: false,
26 | type: 'boolean'
27 | },
28 | save: {
29 | alias: 's',
30 | desc: 'Save flags to config file',
31 | default: false,
32 | type: 'boolean'
33 | },
34 | limit: {
35 | alias: 'l',
36 | desc: 'Limit number of results',
37 | default: 5,
38 | type: 'number'
39 | },
40 | canon: {
41 | alias: 'c',
42 | desc: 'Use canonical',
43 | default: false,
44 | type: 'boolean'
45 | },
46 | dict: {
47 | alias: 'd',
48 | desc: 'Dictionary: ahd, century, cmu, macmillan, wiktionary, webster, wordnet',
49 | default: '',
50 | type: 'string'
51 | },
52 | type: {
53 | alias: 't',
54 | desc: 'Type: ahd, arpabet, gcide-diacritical, ipa',
55 | default: '',
56 | type: 'string'
57 | }
58 | }
59 | exports.handler = (argv) => {
60 | if (process.env.WORDNIK === undefined) throw new Error('Put an API key in environment variable WORDNIK per documentation.')
61 | tools.checkConfig(CFILE)
62 | let config = noon.load(CFILE)
63 | let proceed = false
64 | let reset = false
65 | const stamp = new Date(config.wordnik.date.stamp)
66 | const minutes = df.differenceInMinutes(new Date(), stamp)
67 | const checkStamp = tools.limitWordnik(config)
68 | config = checkStamp[0]
69 | proceed = checkStamp[1]
70 | reset = checkStamp[2]
71 | if (proceed) {
72 | const userConfig = {
73 | wordnik: {
74 | pronounce: {
75 | canon: argv.c,
76 | dict: argv.d,
77 | type: argv.t,
78 | limit: argv.l
79 | }
80 | }
81 | }
82 | if (config.merge) config = _.merge({}, config, userConfig)
83 | if (argv.s && config.merge) noon.save(CFILE, config)
84 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
85 | const theme = themes.loadTheme(config.theme)
86 | if (config.verbose) themes.label(theme, 'down', 'Wordnik')
87 | const word = argv.word
88 | const task = 'pronunciations'
89 | const prefix = 'http://api.wordnik.com:80/v4/word.json/'
90 | const apikey = process.env.WORDNIK
91 | const uri = `${prefix}${word}/${task}?`
92 | const pcont = []
93 | pcont.push(`useCanonical=${config.wordnik.pronounce.canon}&`)
94 | if (config.wordnik.pronounce.dict !== '') pcont.push(`sourceDictionary=${config.wordnik.pronounce.dict}&`)
95 | if (config.wordnik.pronounce.type !== '') pcont.push(`typeFormat=${config.wordnik.pronounce.type}&`)
96 | pcont.push(`limit=${config.wordnik.pronounce.limit}&`)
97 | pcont.push(`api_key=${apikey}`)
98 | const rest = pcont.join('')
99 | let url = `${uri}${rest}`
100 | url = encodeURI(url)
101 | themes.label(theme, 'down', 'Pronunciations')
102 | const tofile = {
103 | type: 'pronunciation',
104 | source: 'http://www.wordnik.com'
105 | }
106 | tofile.word = word
107 | http({ url }, (error, response) => {
108 | if (!error && response.statusCode === 200) {
109 | if (response.headers['x-gg-state'] === 'cached') {
110 | config.wordnik.date.remain++
111 | noon.save(CFILE, config)
112 | if (config.usage) console.log('Cached response, not decrementing usage.')
113 | }
114 | const list = JSON.parse(response.body)
115 | for (let i = 0; i <= list.length - 1; i++) {
116 | const item = list[i]
117 | themes.label(theme, 'right', word, `${item.raw} - Type - ${item.rawType}`)
118 | tofile[[`pronunciation${i}`]] = item.raw
119 | tofile[[`type${i}`]] = item.rawType
120 | }
121 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
122 | if (config.usage) reset ? console.log(`Timestamp expired, not decrementing usage.\n${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour.`) : console.log(`${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
123 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
124 | })
125 | } else throw new Error(`Reached this hour's usage limit of ${config.wordnik.date.limit}.`)
126 | }
127 |
--------------------------------------------------------------------------------
/src/commands/wordnik/relate.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const themes = require('../../themes')
3 | const tools = require('../../tools')
4 |
5 | const _ = require('lodash')
6 | const df = require('date-fns')
7 | const http = require('good-guy-http')()
8 | const noon = require('noon')
9 |
10 | const CFILE = `${process.env.HOME}/.leximaven.noon`
11 |
12 | exports.command = 'relate '
13 | exports.aliases = ['related', 'rel']
14 | exports.desc = 'Wordnik related words'
15 | exports.builder = {
16 | out: {
17 | alias: 'o',
18 | desc: 'Write cson, json, noon, plist, yaml, xml',
19 | default: '',
20 | type: 'string'
21 | },
22 | force: {
23 | alias: 'f',
24 | desc: 'Force overwriting outfile',
25 | default: false,
26 | type: 'boolean'
27 | },
28 | save: {
29 | alias: 's',
30 | desc: 'Save flags to config file',
31 | default: false,
32 | type: 'boolean'
33 | },
34 | limit: {
35 | alias: 'l',
36 | desc: 'Limit results = require(type option',
37 | default: 10,
38 | type: 'number'
39 | },
40 | canon: {
41 | alias: 'c',
42 | desc: 'Use canonical',
43 | default: false,
44 | type: 'boolean'
45 | },
46 | type: {
47 | alias: 't',
48 | desc: 'Relationship types to limit',
49 | default: '',
50 | type: 'string'
51 | }
52 | }
53 | exports.handler = (argv) => {
54 | if (process.env.WORDNIK === undefined) throw new Error('Put an API key in environment variable WORDNIK per documentation.')
55 | tools.checkConfig(CFILE)
56 | let config = noon.load(CFILE)
57 | let proceed = false
58 | let reset = false
59 | const stamp = new Date(config.wordnik.date.stamp)
60 | const minutes = df.differenceInMinutes(new Date(), stamp)
61 | const checkStamp = tools.limitWordnik(config)
62 | config = checkStamp[0]
63 | proceed = checkStamp[1]
64 | reset = checkStamp[2]
65 | if (proceed) {
66 | const userConfig = {
67 | wordnik: {
68 | relate: {
69 | canon: argv.c,
70 | type: argv.t,
71 | limit: argv.l
72 | }
73 | }
74 | }
75 | if (config.merge) config = _.merge({}, config, userConfig)
76 | if (argv.s && config.merge) noon.save(CFILE, config)
77 | if (argv.s && !config.merge) throw new Error("Can't save user config, set option merge to true.")
78 | const theme = themes.loadTheme(config.theme)
79 | if (config.verbose) themes.label(theme, 'down', 'Wordnik')
80 | const word = argv.word
81 | const task = 'relatedWords'
82 | const prefix = 'http://api.wordnik.com:80/v4/word.json/'
83 | const apikey = process.env.WORDNIK
84 | const uri = `${prefix}${word}/${task}?`
85 | const pcont = []
86 | pcont.push(`useCanonical=${config.wordnik.relate.canon}&`)
87 | if (config.wordnik.relate.type !== '') pcont.push(`relationshipTypes=${config.wordnik.relate.type}&`)
88 | pcont.push(`limitPerRelationshipType=${config.wordnik.relate.limit}&`)
89 | pcont.push(`api_key=${apikey}`)
90 | const rest = pcont.join('')
91 | let url = `${uri}${rest}`
92 | url = encodeURI(url)
93 | themes.label(theme, 'down', 'Related words')
94 | const tofile = {
95 | type: 'related words',
96 | source: 'http://www.wordnik.com'
97 | }
98 | tofile.word = word
99 | http({ url }, (error, response) => {
100 | if (!error && response.statusCode === 200) {
101 | if (response.headers['x-gg-state'] === 'cached') {
102 | config.wordnik.date.remain++
103 | noon.save(CFILE, config)
104 | if (config.usage) console.log('Cached response, not decrementing usage.')
105 | }
106 | const list = JSON.parse(response.body)
107 | for (let i = 0; i <= list.length - 1; i++) {
108 | const item = list[i]
109 | themes.label(theme, 'right', item.relationshipType, `${item.words.join(', ')}`)
110 | tofile[[`type${i}`]] = item.relationshipType
111 | tofile[[`words${i}`]] = item.words.join(', ')
112 | }
113 | if (argv.o) tools.outFile(argv.o, argv.f, tofile)
114 | if (config.usage) reset ? console.log(`Timestamp expired, not decrementing usage.\n${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour.`) : console.log(`${config.wordnik.date.remain}/${config.wordnik.date.limit} requests remaining this hour, will reset in ${59 - minutes} minutes.`)
115 | } else throw new Error(`HTTP ${error.statusCode}: ${error.reponse.body}`)
116 | })
117 | } else throw new Error(`Reached this hour's usage limit of ${config.wordnik.date.limit}.`)
118 | }
119 |
--------------------------------------------------------------------------------
/src/leximaven.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | /* eslint max-len: 0, no-unused-expressions: 0 */
3 | const chalk = require('chalk')
4 | const pkg = require('../package.json')
5 | const yargonaut = require('yargonaut')
6 | .style('bold.underline', 'Commands:')
7 | .style('bold.underline', 'Options:')
8 | .style('bold.cyan', 'boolean')
9 | .style('bold.yellow', 'string')
10 | .style('bold.magenta', 'number')
11 | .style('bold.blue', 'default:')
12 | .style('bold.green', 'aliases:')
13 | const yargs = require('yargs')
14 | yargs
15 | .commandDir('commands')
16 | .usage(`${chalk.yellow(`${yargonaut.asFont('leximaven', 'Small Slant')}`)}\n${chalk.bold.underline('Usage:')}\n$0 [options]`)
17 | .help('h')
18 | .alias('h', 'help')
19 | .option('v', {
20 | alias: 'verbose',
21 | type: 'boolean',
22 | desc: 'Verbose output'
23 | })
24 | .version('V', 'Show current version', pkg.version)
25 | .alias('V', 'version')
26 | .global('v')
27 | .demand(1)
28 | .argv
29 |
--------------------------------------------------------------------------------
/src/themes.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len:0 */
2 | const _ = require('lodash')
3 | const chalk = require('chalk')
4 | const fs = require('fs')
5 | const glob = require('glob')
6 | const noon = require('noon')
7 |
8 | let TDIR = null
9 | let themeDirExists = null
10 | try {
11 | fs.statSync('themes')
12 | themeDirExists = true
13 | } catch (e) {
14 | if (e.code === 'ENOENT') themeDirExists = false
15 | }
16 | themeDirExists ? TDIR = 'themes/' : TDIR = `${process.env.NODE_PATH}/leximaven/themes/`
17 |
18 | /**
19 | * The themes module provides useful repetitive theme tasks
20 | * @module Themes
21 | */
22 |
23 | /**
24 | * Loads theme
25 | * @public
26 | * @param {string} theme The name of the theme
27 | * @return {Object} load The style to use
28 | */
29 | exports.loadTheme = (theme) => {
30 | let dirExists = null
31 | let load = null
32 | try {
33 | fs.statSync('themes')
34 | dirExists = true
35 | } catch (e) {
36 | if (e.code === 'ENOENT') dirExists = false
37 | }
38 | const CFILE = `${process.env.HOME}/.leximaven.noon`
39 | const config = noon.load(CFILE)
40 | if (!dirExists && config.verbose) console.log(chalk.white(`${process.cwd()}/themes does not exist, falling back to ${process.env.NODE_PATH}/leximaven/themes.`))
41 | load = noon.load(`${TDIR}${theme}.noon`)
42 | return load
43 | }
44 |
45 | /**
46 | * Gets themes for list command
47 | * @public
48 | * @return {Array} List of theme names
49 | */
50 | exports.getThemes = () => {
51 | const list = []
52 | let dirExists = null
53 | let files = []
54 | try {
55 | fs.statSync('themes')
56 | dirExists = true
57 | } catch (e) {
58 | if (e.code === 'ENOENT') dirExists = false
59 | }
60 | const CFILE = `${process.env.HOME}/.leximaven.noon`
61 | const config = noon.load(CFILE)
62 | if (!dirExists && config.verbose) console.log(chalk.white(`${process.cwd()}/themes does not exist, falling back to ${process.env.NODE_PATH}/leximaven/themes.`))
63 | files = glob.sync(`${TDIR}*.noon`)
64 | for (let i = 0; i <= files.length - 1; i++) {
65 | list.push(files[i].replace(/[a-z0-9/_.]*themes\//, '').replace(/\.noon/, ''))
66 | }
67 | return list
68 | }
69 |
70 | /**
71 | * Prints label, connector, and content
72 | * @public
73 | * @param {Object} theme The style to use
74 | * @param {string} direction 'down' or 'right'
75 | * @param {string} text The label text
76 | * @param {string} [content] The text the label points at
77 | * @return {string} The stylized string to log
78 | */
79 | exports.label = (theme, direction, text, content) => {
80 | const pstyle = _.get(chalk, theme.prefix.style)
81 | const tstyle = _.get(chalk, theme.text.style)
82 | const sstyle = _.get(chalk, theme.suffix.style)
83 | const cnstyle = _.get(chalk, theme.connector.style)
84 | const ctstyle = _.get(chalk, theme.content.style)
85 | let label = `${pstyle(theme.prefix.str)}${tstyle(text)}${sstyle(theme.suffix.str)}`
86 | if (direction === 'right') {
87 | content !== null && content !== undefined ? label = `${label}${cnstyle(theme.connector.str)}${ctstyle(content)}` : label = `${label}`
88 | } else if (direction === 'down') {
89 | content !== null && content !== undefined ? label = `${label}\n${cnstyle(theme.connector.str)}${ctstyle(content)}` : label = `${label}`
90 | } else { throw new Error("Unsupported label direction, use 'down' or 'right'.") }
91 | console.log(label)
92 | return label
93 | }
94 |
--------------------------------------------------------------------------------
/src/tools.js:
--------------------------------------------------------------------------------
1 | /* eslint max-len: 0 */
2 | const chalk = require('chalk')
3 | const df = require('date-fns')
4 | const fs = require('fs-extra')
5 | const noon = require('noon')
6 | const ts = require('term-size')
7 | const wrap = require('wrap-ansi')
8 | const xml2js = require('xml2js')
9 |
10 | const CFILE = `${process.env.HOME}/.leximaven.noon`
11 |
12 | /**
13 | * The tools module provides useful repetitive tasks
14 | * @module Utils
15 | */
16 |
17 | /**
18 | * Onelook's API limit check
19 | * @param {Object} config The current config
20 | * @return {Array} Updated config, proceed boolean, and reset boolean
21 | */
22 | exports.limitOnelook = (config) => {
23 | const c = config
24 | let proceed = false
25 | let reset = false
26 | const stamp = new Date(c.onelook.date.stamp)
27 | const hours = df.differenceInHours(new Date(), stamp)
28 | if (hours < 24) {
29 | c.onelook.date.remain--
30 | } else if (hours >= 24) {
31 | reset = true
32 | c.onelook.date.stamp = new Date().toJSON()
33 | c.onelook.date.remain = c.onelook.date.limit
34 | c.onelook.date.remain--
35 | }
36 | c.onelook.date.remain <= 0 ? c.onelook.date.remain = 0 : proceed = true
37 | noon.save(CFILE, c)
38 | return [c, proceed, reset]
39 | }
40 |
41 | /**
42 | * Datamuse's API limit check
43 | * @param {Object} config The current config
44 | * @return {Array} Updated config, proceed boolean, and reset boolean
45 | */
46 | exports.limitDmuse = (config) => {
47 | const c = config
48 | let proceed = false
49 | let reset = false
50 | const stamp = new Date(c.dmuse.date.stamp)
51 | const hours = df.differenceInHours(new Date(), stamp)
52 | if (hours < 24) {
53 | c.dmuse.date.remain--
54 | } else if (hours >= 24) {
55 | reset = true
56 | c.dmuse.date.stamp = new Date().toJSON()
57 | c.dmuse.date.remain = c.dmuse.date.limit
58 | c.dmuse.date.remain--
59 | }
60 | c.dmuse.date.remain <= 0 ? c.dmuse.date.remain = 0 : proceed = true
61 | noon.save(CFILE, c)
62 | return [c, proceed, reset]
63 | }
64 |
65 | /**
66 | * Rhymebrain's API limit check
67 | * @param {Object} config The current config
68 | * @return {Array} Updated config, proceed boolean, and reset boolean
69 | */
70 | exports.limitRbrain = (config) => {
71 | const c = config
72 | let proceed = false
73 | let reset = false
74 | const stamp = new Date(c.rbrain.date.stamp)
75 | const minutes = df.differenceInMinutes(new Date(), stamp)
76 | if (minutes < 60) {
77 | c.rbrain.date.remain--
78 | } else if (minutes >= 60) {
79 | reset = true
80 | c.rbrain.date.stamp = new Date().toJSON()
81 | c.rbrain.date.remain = c.rbrain.date.limit
82 | c.rbrain.date.remain--
83 | }
84 | c.rbrain.date.remain <= 0 ? c.rbrain.date.remain = 0 : proceed = true
85 | noon.save(CFILE, c)
86 | return [c, proceed, reset]
87 | }
88 |
89 | /**
90 | * Wordnik's API limit check
91 | * @param {Object} config The current config
92 | * @return {Array} Updated config, proceed boolean, and reset boolean
93 | */
94 | exports.limitWordnik = (config) => {
95 | const c = config
96 | let proceed = false
97 | let reset = false
98 | const stamp = new Date(c.wordnik.date.stamp)
99 | const minutes = df.differenceInMinutes(new Date(), stamp)
100 | if (minutes < 60) {
101 | c.wordnik.date.remain--
102 | } else if (minutes >= 60) {
103 | reset = true
104 | c.wordnik.date.stamp = new Date().toJSON()
105 | c.wordnik.date.remain = c.wordnik.date.limit
106 | c.wordnik.date.remain--
107 | }
108 | c.wordnik.date.remain <= 0 ? c.wordnik.date.remain = 0 : proceed = true
109 | noon.save(CFILE, c)
110 | return [c, proceed, reset]
111 | }
112 |
113 | /**
114 | * Checks if a file exists
115 | * @private
116 | * @param {string} path The filename to check.
117 | * @return {boolean} fileExists
118 | */
119 | function checkOutfile (path) {
120 | let fileExists = null
121 | try {
122 | fs.statSync(path)
123 | fileExists = true
124 | } catch (e) {
125 | if (e.code === 'ENOENT') fileExists = false
126 | }
127 | return fileExists
128 | }
129 |
130 | /**
131 | * Converts string to boolean
132 | * @public
133 | * @param {string} value
134 | * @return {boolean} v
135 | */
136 | exports.checkBoolean = (value) => {
137 | let v = value
138 | if (v === 'true') v = true
139 | if (v === 'false') v = false
140 | return v
141 | }
142 |
143 | /**
144 | * Converts a boolean to a 0 or 1
145 | * @param {boolean} value A boolean value
146 | * @return {integer} 0 or 1
147 | */
148 | exports.boolToBin = (value) => {
149 | let r = null
150 | value ? r = 1 : r = 0
151 | return r
152 | }
153 |
154 | /**
155 | * Checks if config exists. If not, prints init message and exits with error code.
156 | * @public
157 | * @param {string} file Configuration filepath
158 | */
159 | exports.checkConfig = (file) => {
160 | try {
161 | fs.statSync(file)
162 | } catch (e) {
163 | if (e.code === 'ENOENT') throw new Error(`No config found at ${file}, run: 'leximaven config init'`)
164 | }
165 | return true
166 | }
167 |
168 | /**
169 | * Checks if object is a single string in an array
170 | * @public
171 | * @param {Object} obj Any object
172 | * @return {Object} Original object or extracted string
173 | */
174 | exports.arrToStr = (obj) => {
175 | let fixed = null
176 | Array.isArray(obj) && obj.length === 1 && typeof obj[0] === 'string' ? fixed = obj[0] : fixed = obj
177 | return fixed
178 | }
179 |
180 | /**
181 | * Strips HTML from a string
182 | * @public
183 | * @param {string} string Text with HTML tags
184 | * @return {string} Plain text string
185 | */
186 | exports.stripHTML = (string) => string.replace(/(<([^>]+)>)/ig, '')
187 |
188 | /**
189 | * Wraps blocks of text
190 | * @param {string} str Long string
191 | * @param {boolean} hard true, soft false
192 | * @param {boolean} wwrap true, column wrap false
193 | * @return {string} ANSI-wrapped string
194 | */
195 | exports.wrapStr = (str, hard, wwrap) => {
196 | const termsize = ts()
197 | return wrap(str, termsize.columns, hard, wwrap)
198 | }
199 |
200 | /**
201 | * Handles data export to file. Supports cson, json, noon, plist, xml, yaml.
202 | * @public
203 | * @param {string} path The desired filepath and extension
204 | * @param {boolean} force Whether to force overwrite
205 | * @param {Object} tofile A numbered object of data points
206 | */
207 | exports.outFile = (path, force, tofile) => {
208 | const match = path.match(/\.([a-z]*)$/i)
209 | const ext = match[1]
210 | const builder = new xml2js.Builder()
211 | if (ext === 'xml') {
212 | if (checkOutfile(path)) {
213 | if (force) {
214 | const xml = builder.buildObject(tofile)
215 | const fd = fs.openSync(path, 'w+')
216 | fs.writeSync(fd, xml)
217 | fs.closeSync(fd)
218 | console.log(chalk.white(`Overwrote ${path} with data.`))
219 | } else console.log(chalk.white(`${path} exists, use -f to force overwrite.`))
220 | } else {
221 | const xml = builder.buildObject(tofile)
222 | const fd = fs.openSync(path, 'w+')
223 | fs.writeSync(fd, xml)
224 | fs.closeSync(fd)
225 | console.log(chalk.white(`Wrote data to ${path}.`))
226 | }
227 | } else if (ext === 'cson' || ext === 'json' || ext === 'noon' || ext === 'plist' || ext === 'yml' || ext === 'yaml') {
228 | if (checkOutfile(path)) {
229 | if (force) {
230 | noon.save(path, tofile)
231 | console.log(chalk.white(`Overwrote ${path} with data.`))
232 | } else console.log(chalk.white(`${path} exists, use -f to force overwrite.`))
233 | } else {
234 | noon.save(path, tofile)
235 | console.log(chalk.white(`Wrote data to ${path}.`))
236 | }
237 | } else if (ext !== 'xml' || ext !== 'cson' || ext !== 'json' || ext !== 'noon' || ext !== 'plist' || ext !== 'yml' || ext !== 'yaml') throw new Error(`Format ${ext} not supported.`)
238 | }
239 |
--------------------------------------------------------------------------------
/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Get definitions for 'catharsis'
4 | leximaven wordnik define catharsis
5 | #Get antonyms for 'noise'
6 | leximaven wordnik relate --canon --type antonym noises
7 | # Pronounce 'quixotic'
8 | leximaven wordnik pronounce quixotic
9 | # Get etymology for 'special'
10 | leximaven wordnik origin special
11 | # Get words that sound like 'blue'
12 | leximaven datamuse get sl=blue
13 | # Get slang/colloquialisms for 'diesel'
14 | leximaven urban diesel
15 | # Get a wordmap for 'ubiquity'
16 | leximaven wordmap ubiquity
17 |
--------------------------------------------------------------------------------
/themes/colonel.noon:
--------------------------------------------------------------------------------
1 | prefix
2 | str ::
3 | style bold.magenta
4 | text
5 | style bold.yellow
6 | content
7 | style white
8 | suffix
9 | str ::
10 | style bold.magenta
11 | connector
12 | str |||
13 | style bold.yellow
14 |
--------------------------------------------------------------------------------
/themes/markup.noon:
--------------------------------------------------------------------------------
1 | prefix
2 | str <
3 | style bold.blue
4 | text
5 | style bold.cyan
6 | content
7 | style white
8 | suffix
9 | str >
10 | style bold.blue
11 | connector
12 | str ->
13 | style bold.green
14 |
--------------------------------------------------------------------------------
/themes/square.noon:
--------------------------------------------------------------------------------
1 | prefix
2 | str [
3 | style bold.green
4 | text
5 | style bold.white
6 | content
7 | style white
8 | suffix
9 | str ]
10 | style bold.green
11 | connector
12 | str →
13 | style bold.cyan
14 |
--------------------------------------------------------------------------------