Skip to content

Commit

Permalink
Merge pull request #27 from AdrieanKhisbe/support-node12-and-goodies
Browse files Browse the repository at this point in the history
Support node12 and goodies
  • Loading branch information
borisdiakur committed Jul 16, 2020
2 parents 10c1b4c + a45c9ad commit 739bcfc
Show file tree
Hide file tree
Showing 11 changed files with 5,279 additions and 1,208 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.DS_Store
node_modules
coverage
.nyc_output
*.log
tmp
11 changes: 11 additions & 0 deletions .nycrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"all": true,
"reporter": [
"lcov",
"text-summary",
"text","html"
],
"include": [
"lib"
]
}
10 changes: 7 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
sudo: false
language: node_js
node_js:
- '9.11.2'
- '10.5.0'
- '8.17.0'
- '10'
- '12'
- '14'

after_script:
- npm run publish-coverage
46 changes: 40 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,48 @@ $ n_ --use_strict
n_ >
```

## Notes
## Repl specificities

### Special character `_`
#### Commands
Some commands are available to facilitate some operations, and are host under `.lodash` repl command:
- `.lodash fp`: switch to lodash/fp
- `.lodash vanilla`: switch to _vanilla_ lodash mode
- `.lodash reset`: switch to initial lodash mode
- `.lodash swap`: switch to the other lodash mode (_vanilla_/_fp_)
- `.lodash current`: output current lodash flavor in use
- `.lodash version`: output lodash version in use

The behavior of assigning `_` to the last evaluated expression is disabled, since lodash is already assigned to `_`.
and the `.lodash help` to have more details about lodash repl commands

### History persistence
#### `__` as _last evaluated expression_
Special character `_` refer to the lodash instance, and cannot hold value of last expression.
To provide the same feature, `__` was introduced:

**n_** stores its session history under `~/.n_repl_history`.
```shell
n_ > 10 + 2
12
n_ > 'number '+ __
'number 12'
```

#### Configuration options

Aside `--fp` and `--use_strict`/`--use-strict`, some other options are available either as CLI flags, or via environment variables.(with a trailing `_N_`)

The two main feature you can control is _History persistance_ and _Prompt Theme_.

| Flag | aliases|Env variable| Description|Default
|-|-|--|-|-|
|`--history-path`|`--history`, `history-file`|`_N_HISTORY_PATH`|Location of repl history file|_`~/.n_repl_history`_|
|`--prompt.symbol`||`_N_PROMPT__SYMBOL`|Symbol to use as `$` prompt|_`>`_|
|`--prompt.name`||`_N_PROMPT__NAME`|Name for the prompt |_`n_`_|
|`--prompt.color.name`||`_N_PROMPT__COLOR__NAME`|Color for prompt name `n_`|`blue`|
|`--prompt.color.symbol`||`_N_PROMPT__COLOR__SYMBOL`|Color for prompt symbol|_`red`_|
|`--prompt.color.flavor`||`_N_PROMPT__COLOR__FLAVOR`|Color for section of prompt about lodash flavor in use|`cyan`|
|`--prompt.color.help`||`_N_PROMPT__COLOR__HELP`|Color for section of prompt about lodash flavor in use|`green`|


About styling, valid colors are: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`,`gray`, and `dim`.

Enjoy!
-----
Enjoy! :rocket:
7 changes: 2 additions & 5 deletions bin/n_
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
#!/usr/bin/env node

var path = require('path')
var fs = require('fs')
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib')

require(lib + '/n_.js')
const n_ = require('..')
n_.main(process.argv.slice(2))
238 changes: 197 additions & 41 deletions lib/n_.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,204 @@
var osHomedir = require('os').homedir()
var path = require('path')
var replHistory = require('repl.history')
const osHomedir = require('os').homedir()
const path = require('path')
const replHistory = require('repl-story')
const c = require('chalk')

const CHALK_STYLES = ['black',
'red',
'green',
'yellow',
'blue',
'magenta',
'cyan',
'white',
'gray',
'dim']

const argsSpec = require('yargs')
.option('fp', {
description: 'Use fp flavor of lodash',
default: false,
boolean: true
})
.option('use_strict', {
description: 'Activate strict mode',
alias: ['use-strict', 's'],
default: false,
boolean: true
})
.option('history-path', {
description: 'Use a custom history filename',
alias: ['history', 'history-file'],
string: true,
default: path.join(osHomedir, '.n_repl_history')
})
.option('prompt.symbol', {
description: 'Prompt symbol for the repl',
string: true,
default: '>'
})
.option('prompt.color.symbol', {
description: 'Color for symbol part of prompt',
default: 'red'
})
.option('prompt.color.flavor', {
description: 'Color for flavor part of prompt',
default: 'cyan'
})
.option('prompt.color.name', {
description: 'Color for name part of prompt',
default: 'blue'
})
.option('prompt.color.help', {
description: 'Color for help highlight',
default: 'green'
})
.option('prompt.name', {
description: 'Base name for the prompt',
string: true,
default: 'n_'
})
.coerce('prompt', prompt => {
for (const [key, color] of Object.entries(prompt.color)) {
if (!CHALK_STYLES.includes(color)) throw new Error(`Unsupported color '${color}' for '${key}' color`)
}
return prompt
})
.fail(message => {
throw new Error(`Invalid provided option: ${message}`)
})
.env('_N')

const argsDefaults = argsSpec.parse([])

// store method reference in case it is overwritten later
var setDescriptor = Object.defineProperty
const setDescriptors = Object.defineProperties

function injectLodashIntoRepl (server, lodashes, promptConfig) {
let currentFlavor = lodashes.initial
let currentLodash = lodashes[currentFlavor]

const { help: helpColor, flavor: flavorColor } = promptConfig.color

const setLodash = flavor => repl => {
currentFlavor = typeof flavor === 'string' ? flavor : flavor()
repl.log(`Setting lodash ${c.bold('_')} to ${c.bold[flavorColor](currentFlavor)} flavor!`)
currentLodash = lodashes[currentFlavor]
repl.setPrompt(promptConfig.makePrompt(currentFlavor))
}

const commandHelps = {
fp: 'set _ to lodash/fp',
vanilla: "set _ to 'vanilla' lodash",
swap: 'change flavor of _ (from vanilla to fp or the reverse)',
reset: 'restore original lodash version used',
current: 'print current flavor of lodash in use',
version: 'print current version of lodash in use'
}
const lodashSubCommands = {
fp: setLodash('fp'),
vanilla: setLodash('vanilla'),
reset: setLodash(lodashes.initial),
swap: setLodash(() => currentFlavor === 'fp' ? 'vanilla' : 'fp'),
current: repl => repl.log(`Current lodash flavor is ${c.bold[flavorColor](currentFlavor)}`),
version: repl => repl.log(`Current lodash version is ${c.bold[flavorColor](currentLodash.VERSION)}`),
help: repl => repl.log([
`${c.bold[helpColor]('.lodash')} enable you to configure the ${c.bold('_')} lodash instance of n_ repl, here are the available sub-commands:`,
...Object.entries(commandHelps).map(([command, help]) => `- ${c.bold[helpColor](command)}: ${help.replace('_', c.bold('_'))}`)
].join('\n'))
}

const clear = typeof server.clearBufferedCommand === 'function' ? server => server.clearBufferedCommand() : server => { server.bufferedCommand = '' }
server.defineCommand('lodash', {
help: 'Configure lodash utils, commands: help, current, swap, fp, vanilla, reset, version',
action: function (input) {
clear(this)
if (!input) {
this.log('Please provide a sub-command for .lodash')
lodashSubCommands.help(this)
} else {
const subcommand = input.split(' ')[0]
const handler = lodashSubCommands[subcommand]
if (!handler) this.log(`there is no '${c.bold.red(subcommand)}' sub-command, see available ones with '.lodash ${c.bold[helpColor]('help')}'`)
else handler(this)
}
this.displayPrompt()
}
})

// inject lodash into the context
setDescriptors(server.context, {
_: {
configurable: true,
enumerable: false,
get: function () {
return currentLodash
},
set: function (val) {
// noop, value will still retrieved by repl
}
},
__: {
// Restore the '_' last value under alias '__'
configurable: true,
enumerable: false,
get: function () {
return server.last
}
}
})
return server
}

function wrapRepl (args) {
const completeArgs = Object.assign({}, argsDefaults, args)
const promptConfig = {
...completeArgs.prompt,
makePrompt (flavor) {
return `${c.bold[this.color.name](this.name)}${flavor ? `:/${c.bold[this.color.flavor](flavor)}` : ''} ${c.bold[this.color.symbol](this.symbol)} `
}
}
const initialPrompt = promptConfig.makePrompt()
const customReplServer = completeArgs.replServer instanceof repl.REPLServer

const server = customReplServer ? completeArgs.replServer : repl.start({
prompt: initialPrompt,
// allow strict mode via command line argument
replMode: completeArgs.useStrict ? repl.REPL_MODE_STRICT : repl.REPL_MODE_SLOPPY
})
if (completeArgs.replServer) server.setPrompt(initialPrompt)

// attach log method, (introduce to be overridable from outside for the tests)
server.log = console.log

// save repl history
replHistory(server, completeArgs.historyPath)

// create new pristine `lodash` instance
const lodashVanilla = require('lodash').runInContext(server.context)
const lodashFp = require('lodash/fp').runInContext(server.context)

injectLodashIntoRepl(server, { vanilla: lodashVanilla, fp: lodashFp, initial: args.fp ? 'fp' : 'vanilla' }, promptConfig)

return server
}

// create REPL server instance
var repl = require('repl')
var server = repl.start({
prompt: 'n_ > ',
// allow strict mode via command line argument
replMode: process.argv.indexOf('--use_strict') !== -1 ? repl.REPL_MODE_STRICT : repl.REPL_MODE_MAGIC
})

// save repl history
replHistory(server, path.join(osHomedir, '.n_repl_history'))

// create new pristine `lodash` instance
var _ = require('lodash').runInContext(server.context)

var lodashToInject = process.argv.indexOf('--fp') === -1 ? _ : require(path.join('lodash', 'fp')).runInContext(server.context)

// state vars
var prevVal = lodashToInject
var currVal = lodashToInject

// inject lodash into the context
setDescriptor(server.context, '_', {
configurable: true,
enumerable: false,
get: function () {
return currVal
},
set: function (val) {
prevVal = currVal
currVal = val
const repl = require('repl')

function main (argv) {
try {
const args = argsSpec.parse(argv)
wrapRepl(args)
} catch (err) {
console.error(c.bold.red(err.message))
process.exit(1)
}
})
}

var events = server._events
events.line = _.wrap(events.line, function (line, cmd) {
line[0](cmd) // actual command execution
line[1](cmd) // history persistance
currVal = prevVal
})
module.exports = { main, wrapRepl }

module.exports = server
// istanbul ignore next
if (!module.parent) {
main(process.argv.slice(2))
}
Loading

0 comments on commit 739bcfc

Please sign in to comment.