distinguish
Advanced tools
Comparing version 0.1.3 to 0.1.5
{ | ||
"name": "distinguish", | ||
"version": "0.1.3", | ||
"version": "0.1.5", | ||
"description": "Effortless renaming, minification, and namespacing for CSS class names, IDs, and just about anything else.", | ||
@@ -27,2 +27,3 @@ "main": "out/cli.js", | ||
"@types/node": "^10.12.2", | ||
"chokidar": "^2.0.4", | ||
"ts-node": "^7.0.1", | ||
@@ -29,0 +30,0 @@ "typescript": "^3.1.6" |
@@ -13,3 +13,3 @@ CSS is great, but isn't it tricky to namespace class names safely? | ||
Whereas before you might write a CSS class as `.search` or an ID as `#search`, now you write `_cls-search` and `_id-search`. This does a few things. | ||
Whereas before you might write a CSS class as `.search` or an ID as `#search`, now you write `._cls-search` and `#_id-search`. This does a few things. | ||
@@ -53,3 +53,3 @@ * Tells Distinguish that you are dealing with `cls`, a CSS class type, and `id`, an ID type. By keeping track, Distinguish knows which context the name `search` is in and can work its magic accordingly. | ||
That's it. No tricks or special magic. Just pure regular expression parsing and an intelligent naming module that can keep track of multiple types. And a nice perk is that this naming mechanism works without compiling as well as long as there's no naming collisions. | ||
That's it. No tricks or special magic. Just pure regular expression parsing and an intelligent naming module that can keep track of multiple types. And a nice perk is that the code will execute fine without running Distinguish so long as there are no naming collisions across modules (but more on that later). | ||
@@ -93,6 +93,6 @@ That's a taste of Distinguish, a renaming tool that works on any file and can be used in many different ways. But it can also do much more, like namespace directories to avoid cross-module clashing, reserve certain names, and report unused dependencies. | ||
Now run Distinguish: | ||
Now run Distinguish (if you want to watch for changes, add `-w`): | ||
```bash | ||
npx distinguish | ||
npx distinguish rename | ||
``` | ||
@@ -143,3 +143,3 @@ | ||
For example, you could add the type `fn` and then have your JavaScript functions automatically minified (e.g. `_fn$parse()` → `a`) — though I would never recommend doing this. Just use a JS minifier like Uglify or Closure compiler instead that actually understands your code's structure. | ||
For example, you could add the type `fn` and then have your JavaScript functions automatically minified (e.g. `_fn$parse()` → `a`) — though I would recommend using an intelligent JS minifier instead. | ||
@@ -152,6 +152,4 @@ ### Exclude | ||
Distinguish specially handles any files named `.namespec` that it encounters in its crawl. The namespec file specifies the *namespace* of the current directory. Namespaces are covered more in the next section — they are essentially modules that treat instances of the same name differently to avoid collisions. | ||
Distinguish specially handles any files named `.namespec` that it encounters in its crawl. The namespec file specifies the *namespace* of the current directory. The namespec file can additionally import names from other namespaces as well as reserve certain names to be globally avoided in renaming. | ||
The namespec file can additionally import names from other namespaces as well as reserve certain names to be globally avoided in renaming. | ||
### Namespaces | ||
@@ -158,0 +156,0 @@ |
147
src/cli.ts
#!/usr/bin/env node | ||
import {logStyle, SUCCESS, FAIL, BOLD} from './log'; | ||
import {logStyle, SUCCESS, FAIL, BOLD, STATUS, WARN, STATUS_BOLD} from './log'; | ||
import fs from 'fs'; | ||
@@ -22,2 +22,6 @@ import path from 'path'; | ||
const RESET_TO_APPLY = '\nConfig changed. Run again to pull in latest config'; | ||
const POLL_INTERVAL = 50; // pool watch events for this many millseconds | ||
const DEFAULT_CONFIG_FN = 'distinguish.config.js'; | ||
@@ -36,2 +40,11 @@ const BINARY_NAME = 'distinguish'; | ||
function configMissing(path: string) { | ||
return `Unable to read in ${path}. | ||
Maybe you need to create a config file first by running: | ||
distinguish init | ||
`; | ||
} | ||
abstract class CLIParser { | ||
@@ -94,2 +107,3 @@ constructor( | ||
exclude?: RegExp[]; | ||
watch?: boolean; | ||
} | ||
@@ -187,2 +201,9 @@ | ||
if (this.consumeOption(['-w', '--watch'])) { | ||
expectConfig = true; | ||
opts.watch = true; | ||
this.advance(); | ||
continue; | ||
} | ||
if (this.consumeOption(['-n', '--incrementer'])) { | ||
@@ -223,2 +244,3 @@ expectIncrementer = true; | ||
opts.configFile = this.stream[0]; | ||
if (opts.configFile.startsWith('-')) return this.showUsage(); | ||
expectConfig = false; | ||
@@ -243,2 +265,8 @@ this.advance(); | ||
} | ||
if (!this.fs.existsSync(opts.configFile)) { | ||
if (!this.returnOptsOnly) { | ||
logStyle(FAIL, configMissing(opts.configFile)); | ||
} | ||
return this.showUsage(); | ||
} | ||
const settings = this.requireFn(opts.configFile).default; | ||
@@ -248,11 +276,3 @@ | ||
if (!this.returnOptsOnly) { | ||
logStyle( | ||
FAIL, | ||
`Unable to read in ${opts.configFile}. | ||
Maybe you need to create a config file first by running: | ||
distinguish init | ||
` | ||
); | ||
logStyle(FAIL, configMissing(opts.configFile)); | ||
} | ||
@@ -273,8 +293,49 @@ return this.showUsage(); | ||
console.log(); | ||
const distinguisher = new Distinguisher( | ||
let distinguisher = new Distinguisher( | ||
opts as DistinguishConfig, | ||
fs, | ||
path.dirname | ||
this.fs, | ||
this.dirname, | ||
!this.returnOptsOnly | ||
); | ||
distinguisher.run(); | ||
if (opts.watch != null) { | ||
const chokidar = this.requireFn('chokidar'); | ||
let count = 1; | ||
let timer: any = setTimeout(() => (timer = null), POLL_INTERVAL); | ||
chokidar | ||
.watch(opts.configFile) | ||
.on('change', () => { | ||
logStyle(FAIL, RESET_TO_APPLY); | ||
process.exit(0); | ||
}) | ||
.on('unlink', () => { | ||
logStyle(FAIL, RESET_TO_APPLY); | ||
process.exit(0); | ||
}); | ||
chokidar | ||
.watch(opts.inputDir, {ignored: opts.exclude != null ? opts.exclude : []}) | ||
.on('all', (event: any, path: string) => { | ||
if (opts.configFile != null && path == opts.configFile) { | ||
logStyle(FAIL, RESET_TO_APPLY); | ||
process.exit(0); | ||
} | ||
if (timer == null) { | ||
timer = setTimeout(() => { | ||
logStyle( | ||
STATUS_BOLD, | ||
`\n\nFiles changed, re-distinguishing (#${count++})` | ||
); | ||
distinguisher.run(); | ||
timer = null; | ||
}, POLL_INTERVAL); | ||
} | ||
}); | ||
} | ||
} | ||
@@ -285,3 +346,37 @@ return {opts}; | ||
showUsage(): CLIResult { | ||
return (this.parent as CLI).showUsage(); | ||
if (!this.returnOptsOnly) { | ||
console.log(`Usage: ${BINARY_NAME} rename [options] | ||
rename and namespace files recursively in a directory | ||
Options: | ||
-c, --config [fn] Load all the settings from a config file. | ||
(default if no value passed: ${DEFAULT_CONFIG_FN}) | ||
-w, --watch Watch the input directory for any changes. Re-run | ||
automatically if anything changes in the input directory or | ||
any of its sub-directories. | ||
Config options / overrides: | ||
-n, --incrementer <str> Specify the incrementer to use. | ||
Options are 'simple', 'module', or 'minimal' | ||
(default if no config specified: simple) | ||
-t, --types <list> Specify a list of types to rename | ||
(default if no config specified: cls,id) | ||
-i, --inputDir <dir> The input directory to use | ||
(this arg is mandatory if no config is specified) | ||
-o, --outputDir <dir> The output directory to use | ||
(this arg is mandatory if no config is specified) | ||
-e, --exclude <list> Regular expression of paths to exclude renaming. | ||
It is recommended to set this in a config file to | ||
have more control. | ||
(default: empty list) | ||
`); | ||
process.exit(1); | ||
} | ||
return {showUsage: 'rename'}; | ||
} | ||
@@ -360,2 +455,15 @@ } | ||
if (this.consumeOption(['rename'])) { | ||
return new RenameCLI( | ||
this.stream.slice(1), | ||
this.fs, | ||
this.requireFn, | ||
this.dirname, | ||
this.join, | ||
this.cwd, | ||
this.returnOptsOnly, | ||
this | ||
).process(); | ||
} | ||
if (this.consumeOption(['help'])) { | ||
@@ -391,12 +499,3 @@ // Show help menus. | ||
return new RenameCLI( | ||
this.stream, | ||
this.fs, | ||
this.requireFn, | ||
this.dirname, | ||
this.join, | ||
this.cwd, | ||
this.returnOptsOnly, | ||
this | ||
).process(); | ||
return this.showUsage(); | ||
} | ||
@@ -403,0 +502,0 @@ |
@@ -61,3 +61,4 @@ import {Renamer} from './renamer'; | ||
readonly fs: BaseFs, | ||
readonly dirnameFn: (path: string) => string | ||
readonly dirnameFn: (path: string) => string, | ||
readonly logging: boolean = true | ||
) { | ||
@@ -159,3 +160,3 @@ const incrementer = incrementers[distinguishConfig.incrementer] as { | ||
if (hadMatches) { | ||
if (this.logging && hadMatches) { | ||
logStyle( | ||
@@ -172,13 +173,15 @@ STATUS, | ||
const overallTime = Date.now() - startTime; | ||
logStyle(BOLD, `\nWrote output in ${overallTime / 1000}s`); | ||
if (this.logging) logStyle(BOLD, `\nWrote output in ${overallTime / 1000}s`); | ||
const danglers = this.rootRenamer.danglingImports(); | ||
if (danglers.length > 0) console.log('\n'); | ||
if (this.logging && danglers.length > 0) console.log('\n'); | ||
for (const {sourceNamespace, importNamespace, type, name} of danglers) { | ||
logStyle( | ||
WARN, | ||
`Dangling import: ${sourceNamespace} imports unused {type: ${type}, name: ${name}} from ${importNamespace}` | ||
); | ||
if (this.logging) { | ||
logStyle( | ||
WARN, | ||
`Dangling import: ${sourceNamespace} imports unused {type: ${type}, name: ${name}} from ${importNamespace}` | ||
); | ||
} | ||
} | ||
} | ||
} |
export const PASS = ['32']; // green | ||
export const SUCCESS = ['32', '1']; // green, bold | ||
export const FAIL = ['31', '1']; // red, bold | ||
export const STATUS = ['37']; // gray | ||
export const STATUS = ['90']; // gray | ||
export const STATUS_BOLD = ['90', '1']; // gray, bold | ||
export const WARN = ['95']; // magenta | ||
@@ -6,0 +7,0 @@ export const BOLD = ['1']; // bold |
@@ -431,3 +431,3 @@ import {Renamer} from './renamer'; | ||
const d = new Distinguisher(config, fs, fs.dirname); | ||
const d = new Distinguisher(config, fs, fs.dirname, false); | ||
d.run(); | ||
@@ -466,3 +466,3 @@ | ||
const d = new Distinguisher(config, fs, fs.dirname); | ||
const d = new Distinguisher(config, fs, fs.dirname, false); | ||
d.run(); | ||
@@ -541,3 +541,3 @@ | ||
const d = new Distinguisher(config, fs, fs.dirname); | ||
const d = new Distinguisher(config, fs, fs.dirname, false); | ||
d.run(); | ||
@@ -617,5 +617,5 @@ | ||
t.assertObjectEquals(cli('help init'), {showUsage: 'init'}); | ||
t.assertObjectEquals(cli('help rename'), {showUsage: 'base'}); | ||
t.assertObjectEquals(cli('help rename'), {showUsage: 'rename'}); | ||
t.assertObjectEquals(cli('--invalid-option'), {showUsage: 'base'}); | ||
t.assertObjectEquals(cli('rename --invalid-option'), {showUsage: 'base'}); | ||
t.assertObjectEquals(cli('rename --invalid-option'), {showUsage: 'rename'}); | ||
@@ -638,5 +638,5 @@ // Version | ||
t.test('distinguishCliRenameNoConfig', () => { | ||
const result = cli(''); | ||
const result = cli('rename'); | ||
// File won't exist yet. | ||
t.assertEquals(result.showUsage, 'base'); | ||
t.assertEquals(result.showUsage, 'rename'); | ||
}); | ||
@@ -667,9 +667,9 @@ | ||
for (const cmd of [ | ||
'', | ||
'-c', | ||
'-c distinguish.config.js', | ||
'--config', | ||
'--config distinguish.config.js', | ||
'rename ', | ||
'rename -c', | ||
'rename -c distinguish.config.js', | ||
'rename --config', | ||
'rename --config distinguish.config.js', | ||
]) { | ||
const result = cli('', fs => { | ||
const result = cli(cmd, fs => { | ||
fs.writeFileSync('distinguish.config.js', getConfig()); | ||
@@ -694,4 +694,4 @@ }); | ||
for (const cmd of [ | ||
'-c specification/config.js', | ||
'--config specification/config.js', | ||
'rename -c specification/config.js', | ||
'rename --config specification/config.js', | ||
]) { | ||
@@ -718,3 +718,3 @@ const result = cli(cmd, fs => { | ||
const result = cli( | ||
'-c spec/settings/config.js -n minimal -t dog,cat,hen -i input/src/ -o dest/ -e dog,cat', | ||
'rename -c spec/settings/config.js -n minimal -t dog,cat,hen -i input/src/ -o dest/ -e dog,cat', | ||
fs => { | ||
@@ -737,1 +737,20 @@ fs.writeFileSync('spec/settings/config.js', getConfig()); | ||
}); | ||
t.test('distinguishCliWatch', () => { | ||
const result = cli('rename -c spec/settings/config.js -w', fs => { | ||
fs.writeFileSync('spec/settings/config.js', getConfig()); | ||
}); | ||
// Let's check we get a matching config. | ||
t.assert(result.opts); | ||
const opts = result.opts as RenameOptions; | ||
t.assertEquals(opts, { | ||
configFile: 'spec/settings/config.js', | ||
incrementer: 'simple', | ||
types: ['cls', 'id'], | ||
inputDir: 'src/', | ||
outputDir: 'out/', | ||
exclude: [], | ||
watch: true, | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
166611
26
4050
4
284