feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

21
smart-app-city/frontend/node_modules/logkitty/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Paweł Trysła
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

135
smart-app-city/frontend/node_modules/logkitty/README.md generated vendored Normal file
View File

@@ -0,0 +1,135 @@
# logkitty
[![Version][version]][package]
[![PRs Welcome][prs-welcome-badge]][prs-welcome]
[![MIT License][license-badge]][license]
[![Chat][chat-badge]][chat]
[![Code of Conduct][coc-badge]][coc]
Display __pretty__ Android and iOS logs __without Android Studio or Console.app__, with __intuitive__ Command Line Interface.
![Demo](./logkitty.gif)
## Installation
```sh
yarn global add logkitty
```
Or if you prefer having it locally:
```sh
yarn add -D logkitty
yarn logkitty --help
```
## Usage
```sh
logkitty <platform> <command> [options]
```
### Command line help
You can inspect available platforms, command and options for a given platform by adding `-h` at the end, for example:
```sh
logkitty -h # prints available platforms and global options
logkitty android -h # prints commands and options for android
logkitty android tag -h # prints tag command syntax and options for android
```
### Commands
* platform: `android`:
* `tag <tags...>` - Show logs with matching tags.
* `app <appId>` - Show logs from application with given identifier.
* `match <regexes...>` - Show logs matching given patterns (all regexes have flags `g` and `m`).
* `custom <patterns...>` - Use custom [patters supported by Logcat](https://developer.android.com/studio/command-line/logcat#filteringOutput).
* `all` - Show all logs.
* platform: `ios`:
* `tag <tags...>` - Show logs with matching tags (where tag is usually a name of the app).
* `match <regexes...>` - Show logs matching given patterns (all regexes have flags `g` and `m`).
* `all` - Show all logs.
### Options
* common:
* `-h, --help` - Display help
* `-v, --version` - Display version
* platform `android`:
`tag`, `app`, `match` and `all` commands support additional priority filtering options (sorted by priority):
* `-U, -u` - Unknown priority (lowest)
* `-v, -v` - Verbose priority
* `-D, -d` - Debug priority (default)
* `-I, -i` - Info priority
* `-W, -w` - Warn priority
* `-E, -e` - Error priority
* `-F, -f` - Fatal priority
* `-S, -s` - Silent priority (highest)
For example `logkitty android all -W` will display all logs with priority __warn__, __error__ and __fatal__.
* platform `ios`:
`tag`, `match` and `all` commands support additional level filtering options:
* `-D, -d` - Debug level
* `-I, -i` - Info level
* `-E, -e` - Error level
### Examples
Show all logs with tag `ReactNativeJS` (and default priority - __debug and above__):
```sh
logkitty android tag ReactNativeJS
logkitty ios tag ReactNativeJS
```
Show all logs with priority __info and above__ from application with identifier `com.example.myApplication`:
```sh
logkitty android app com.example.myApplication -i
```
Show all logs matching `/CodePush/gm` regex:
```sh
logkitty android match CodePush
logkitty ios match CodePush
```
Show all logs with priority __error__ or __fatal__ for Android and __error_ level for iOS:
```sh
logkitty android all -e
logkitty ios all -e
```
Show logs using custom patterns - silence all logs and display only the onces with tag `my-tag` and priority __debug and above__:
```sh
logkitty android custom *:S my-tag:D
```
### Node API
If your building a tool and want to use Node API, head over to [Node API documentation](./docs/NODE_API.md).
<!-- badges (common) -->
[license-badge]: https://img.shields.io/npm/l/logkitty.svg?style=flat-square
[license]: https://opensource.org/licenses/MIT
[prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
[prs-welcome]: http://makeapullrequest.com
[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
[coc]: https://github.com/zamotany/logkitty/blob/master/CODE_OF_CONDUCT.md
[chat-badge]: https://img.shields.io/badge/chat-discord-brightgreen.svg?style=flat-square&colorB=7289DA&logo=discord
[chat]: https://discord.gg/zwR2Cdh
[version]: https://img.shields.io/npm/v/logkitty.svg?style=flat-square
[package]: https://www.npmjs.com/package/logkitty

View File

@@ -0,0 +1,2 @@
#!/usr/bin/env node
require('../build/cli');

View File

@@ -0,0 +1,12 @@
import { IFilter, Entry } from '../types';
export default class AndroidFilter implements IFilter {
private readonly minPriority;
private filter;
constructor(minPriority?: number);
setFilterByTag(tags: string[]): void;
setFilterByApp(applicationId: string, adbPath?: string): void;
setFilterByMatch(regexes: RegExp[]): void;
setCustomFilter(patterns: string[]): void;
shouldInclude(entry: Entry): boolean;
}
//# sourceMappingURL=AndroidFilter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AndroidFilter.d.ts","sourceRoot":"","sources":["../../src/android/AndroidFilter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAM1C,MAAM,CAAC,OAAO,OAAO,aAAc,YAAW,OAAO;IACnD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAS;gBAEX,WAAW,GAAE,MAAU;IAQnC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE;IAU7B,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAOtD,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE;IAalC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE;IAoBlC,aAAa,CAAC,KAAK,EAAE,KAAK;CAG3B"}

View File

@@ -0,0 +1,67 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _adb = require("./adb");
var _constants = require("./constants");
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class AndroidFilter {
constructor(minPriority = 0) {
_defineProperty(this, "minPriority", void 0);
_defineProperty(this, "filter", void 0);
this.minPriority = minPriority; // Default filter by all
this.filter = entry => {
return entry.priority >= this.minPriority;
};
}
setFilterByTag(tags) {
this.filter = entry => {
return Boolean(entry.priority >= this.minPriority && entry.tag && tags.indexOf(entry.tag) > -1);
};
}
setFilterByApp(applicationId, adbPath) {
const pid = (0, _adb.getApplicationPid)(applicationId, adbPath);
this.filter = entry => {
return entry.priority >= this.minPriority && entry.pid === pid;
};
}
setFilterByMatch(regexes) {
this.filter = entry => {
return entry.priority >= this.minPriority && Boolean(regexes.find(reg => Boolean(entry.messages.find(message => reg.test(message)))));
};
}
setCustomFilter(patterns) {
const tagFilters = patterns.reduce((acc, pattern) => {
const [tag, priority] = pattern.split(':');
return { ...acc,
[tag]: _constants.Priority.fromLetter(priority)
};
}, {});
this.filter = entry => {
return entry.tag && entry.priority >= (tagFilters[entry.tag] || _constants.Priority.SILENT) || entry.priority >= (tagFilters['*'] || _constants.Priority.UNKNOWN);
};
}
shouldInclude(entry) {
return this.filter(entry);
}
}
exports.default = AndroidFilter;
//# sourceMappingURL=AndroidFilter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/android/AndroidFilter.ts"],"names":["AndroidFilter","constructor","minPriority","filter","entry","priority","setFilterByTag","tags","Boolean","tag","indexOf","setFilterByApp","applicationId","adbPath","pid","setFilterByMatch","regexes","find","reg","messages","message","test","setCustomFilter","patterns","tagFilters","reduce","acc","pattern","split","Priority","fromLetter","SILENT","UNKNOWN","shouldInclude"],"mappings":";;;;;;;AACA;;AACA;;;;AAIe,MAAMA,aAAN,CAAuC;AAIpDC,EAAAA,WAAW,CAACC,WAAmB,GAAG,CAAvB,EAA0B;AAAA;;AAAA;;AACnC,SAAKA,WAAL,GAAmBA,WAAnB,CADmC,CAEnC;;AACA,SAAKC,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aAAOA,KAAK,CAACC,QAAN,IAAkB,KAAKH,WAA9B;AACD,KAFD;AAGD;;AAEDI,EAAAA,cAAc,CAACC,IAAD,EAAiB;AAC7B,SAAKJ,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aAAOI,OAAO,CACZJ,KAAK,CAACC,QAAN,IAAkB,KAAKH,WAAvB,IACEE,KAAK,CAACK,GADR,IAEEF,IAAI,CAACG,OAAL,CAAaN,KAAK,CAACK,GAAnB,IAA0B,CAAC,CAHjB,CAAd;AAKD,KAND;AAOD;;AAEDE,EAAAA,cAAc,CAACC,aAAD,EAAwBC,OAAxB,EAA0C;AACtD,UAAMC,GAAG,GAAG,4BAAkBF,aAAlB,EAAiCC,OAAjC,CAAZ;;AACA,SAAKV,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aAAOA,KAAK,CAACC,QAAN,IAAkB,KAAKH,WAAvB,IAAsCE,KAAK,CAACU,GAAN,KAAcA,GAA3D;AACD,KAFD;AAGD;;AAEDC,EAAAA,gBAAgB,CAACC,OAAD,EAAoB;AAClC,SAAKb,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aACEA,KAAK,CAACC,QAAN,IAAkB,KAAKH,WAAvB,IACAM,OAAO,CACLQ,OAAO,CAACC,IAAR,CAAcC,GAAD,IACXV,OAAO,CAACJ,KAAK,CAACe,QAAN,CAAeF,IAAf,CAAqBG,OAAD,IAAqBF,GAAG,CAACG,IAAJ,CAASD,OAAT,CAAzC,CAAD,CADT,CADK,CAFT;AAQD,KATD;AAUD;;AAEDE,EAAAA,eAAe,CAACC,QAAD,EAAqB;AAClC,UAAMC,UAAqC,GAAGD,QAAQ,CAACE,MAAT,CAC5C,CAACC,GAAD,EAAiCC,OAAjC,KAAqD;AACnD,YAAM,CAAClB,GAAD,EAAMJ,QAAN,IAAkBsB,OAAO,CAACC,KAAR,CAAc,GAAd,CAAxB;AACA,aAAO,EACL,GAAGF,GADE;AAEL,SAACjB,GAAD,GAAOoB,oBAASC,UAAT,CAAoBzB,QAApB;AAFF,OAAP;AAID,KAP2C,EAQ5C,EAR4C,CAA9C;;AAUA,SAAKF,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aACGA,KAAK,CAACK,GAAN,IACCL,KAAK,CAACC,QAAN,KAAmBmB,UAAU,CAACpB,KAAK,CAACK,GAAP,CAAV,IAAyBoB,oBAASE,MAArD,CADF,IAEA3B,KAAK,CAACC,QAAN,KAAmBmB,UAAU,CAAC,GAAD,CAAV,IAAmBK,oBAASG,OAA/C,CAHF;AAKD,KAND;AAOD;;AAEDC,EAAAA,aAAa,CAAC7B,KAAD,EAAe;AAC1B,WAAO,KAAKD,MAAL,CAAYC,KAAZ,CAAP;AACD;;AAhEmD","sourcesContent":["import { IFilter, Entry } from '../types';\nimport { getApplicationPid } from './adb';\nimport { Priority } from './constants';\n\ntype Filter = (entry: Entry) => boolean;\n\nexport default class AndroidFilter implements IFilter {\n private readonly minPriority: number;\n private filter: Filter;\n\n constructor(minPriority: number = 0) {\n this.minPriority = minPriority;\n // Default filter by all\n this.filter = (entry: Entry) => {\n return entry.priority >= this.minPriority;\n };\n }\n\n setFilterByTag(tags: string[]) {\n this.filter = (entry: Entry) => {\n return Boolean(\n entry.priority >= this.minPriority &&\n entry.tag &&\n tags.indexOf(entry.tag) > -1\n );\n };\n }\n\n setFilterByApp(applicationId: string, adbPath?: string) {\n const pid = getApplicationPid(applicationId, adbPath);\n this.filter = (entry: Entry) => {\n return entry.priority >= this.minPriority && entry.pid === pid;\n };\n }\n\n setFilterByMatch(regexes: RegExp[]) {\n this.filter = (entry: Entry) => {\n return (\n entry.priority >= this.minPriority &&\n Boolean(\n regexes.find((reg: RegExp) =>\n Boolean(entry.messages.find((message: string) => reg.test(message)))\n )\n )\n );\n };\n }\n\n setCustomFilter(patterns: string[]) {\n const tagFilters: { [key: string]: number } = patterns.reduce(\n (acc: { [key: string]: number }, pattern: string) => {\n const [tag, priority] = pattern.split(':');\n return {\n ...acc,\n [tag]: Priority.fromLetter(priority),\n };\n },\n {}\n );\n this.filter = (entry: Entry) => {\n return (\n (entry.tag &&\n entry.priority >= (tagFilters[entry.tag] || Priority.SILENT)) ||\n entry.priority >= (tagFilters['*'] || Priority.UNKNOWN)\n );\n };\n }\n\n shouldInclude(entry: Entry) {\n return this.filter(entry);\n }\n}\n"],"file":"AndroidFilter.js"}

View File

@@ -0,0 +1,8 @@
import { IParser, Entry } from '../types';
export default class AndroidParser implements IParser {
static timeRegex: RegExp;
static headerRegex: RegExp;
splitMessages(raw: string): string[];
parseMessages(messages: string[]): Entry[];
}
//# sourceMappingURL=AndroidParser.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AndroidParser.d.ts","sourceRoot":"","sources":["../../src/android/AndroidParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,CAAC,OAAO,OAAO,aAAc,YAAW,OAAO;IACnD,MAAM,CAAC,SAAS,EAAE,MAAM,CAAoD;IAC5E,MAAM,CAAC,WAAW,EAAE,MAAM,CAAkC;IAE5D,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE;IAepC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE;CAmD3C"}

View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _dayjs = _interopRequireDefault(require("dayjs"));
var _constants = require("./constants");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class AndroidParser {
splitMessages(raw) {
const messages = [];
let data = raw.toString();
let match = data.match(AndroidParser.timeRegex);
while (match) {
const timeHeader = match[0];
data = data.slice((match.index || 0) + timeHeader.length);
const nextMatch = data.match(AndroidParser.timeRegex);
const body = nextMatch ? data.slice(0, nextMatch.index) : data;
messages.push(`${timeHeader} ${body}`);
match = nextMatch;
}
return messages;
}
parseMessages(messages) {
return messages.map(rawMessage => {
const timeMatch = rawMessage.match(AndroidParser.timeRegex);
if (!timeMatch) {
throw new Error(`Time regex was not matched in message: ${rawMessage}`);
}
const headerMatch = rawMessage.slice(timeMatch[0].length).match(AndroidParser.headerRegex) || ['', 'U', 'unknown', '-1'];
const [, priority, tag, pid] = headerMatch;
return {
platform: 'android',
date: (0, _dayjs.default)().set('month', parseInt(timeMatch[1], 10)).set('day', parseInt(timeMatch[2], 10)).set('hour', parseInt(timeMatch[3], 10)).set('minute', parseInt(timeMatch[4], 10)).set('second', parseInt(timeMatch[5], 10)).set('millisecond', 0),
pid: parseInt(pid.trim(), 10) || 0,
priority: _constants.Priority.fromLetter(priority),
tag: tag.trim() || 'unknown',
messages: [rawMessage.slice(timeMatch[0].length + headerMatch[0].length).trim()]
};
}).reduce((acc, entry) => {
if (acc.length > 0 && acc[acc.length - 1].date.isSame(entry.date) && acc[acc.length - 1].tag === entry.tag && acc[acc.length - 1].pid === entry.pid && acc[acc.length - 1].priority === entry.priority) {
acc[acc.length - 1].messages.push(...entry.messages);
return acc;
}
return [...acc, entry];
}, []);
}
}
exports.default = AndroidParser;
_defineProperty(AndroidParser, "timeRegex", /(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}).\d{3}/m);
_defineProperty(AndroidParser, "headerRegex", /^\s*(\w)\/(.+)\(([\s\d]+)\):/);
//# sourceMappingURL=AndroidParser.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,7 @@
/// <reference types="node" />
import { ChildProcess } from 'child_process';
export declare function runAndroidLoggingProcess(adbPath?: string): ChildProcess;
export declare function getAdbPath(customPath?: string): string;
export declare function spawnLogcatProcess(adbPath: string): ChildProcess;
export declare function getApplicationPid(applicationId: string, adbPath?: string): number;
//# sourceMappingURL=adb.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"adb.d.ts","sourceRoot":"","sources":["../../src/android/adb.ts"],"names":[],"mappings":";AAAA,OAAO,EAAuB,YAAY,EAAE,MAAM,eAAe,CAAC;AAUlE,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAGvE;AAED,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAoBhE;AAED,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAsBR"}

View File

@@ -0,0 +1,65 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.runAndroidLoggingProcess = runAndroidLoggingProcess;
exports.getAdbPath = getAdbPath;
exports.spawnLogcatProcess = spawnLogcatProcess;
exports.getApplicationPid = getApplicationPid;
var _child_process = require("child_process");
var _path = _interopRequireDefault(require("path"));
var _errors = require("../errors");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function runAndroidLoggingProcess(adbPath) {
const execPath = getAdbPath(adbPath);
return spawnLogcatProcess(execPath);
}
function getAdbPath(customPath) {
if (customPath) {
return _path.default.resolve(customPath);
}
return process.env.ANDROID_HOME ? `${process.env.ANDROID_HOME}/platform-tools/adb` : 'adb';
}
function spawnLogcatProcess(adbPath) {
try {
(0, _child_process.execFileSync)(adbPath, ['logcat', '-c']);
} catch (error) {
throw new _errors.CodeError(_errors.ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER, error.message);
}
try {
return (0, _child_process.spawn)(adbPath, ['logcat', '-v', 'time', 'process', 'tag'], {
stdio: 'pipe'
});
} catch (error) {
throw new _errors.CodeError(_errors.ERR_ANDROID_CANNOT_START_LOGCAT, error.message);
}
}
function getApplicationPid(applicationId, adbPath) {
let output;
try {
output = (0, _child_process.execFileSync)(getAdbPath(adbPath), ['shell', 'pidof', '-s', applicationId]);
} catch (error) {
throw new _errors.CodeError(_errors.ERR_ANDROID_CANNOT_GET_APP_PID, error.message);
}
const pid = output ? parseInt(output.toString(), 10) : NaN;
if (isNaN(pid)) {
throw new _errors.CodeError(_errors.ERR_ANDROID_UNPROCESSABLE_PID);
}
return pid;
}
//# sourceMappingURL=adb.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/android/adb.ts"],"names":["runAndroidLoggingProcess","adbPath","execPath","getAdbPath","spawnLogcatProcess","customPath","path","resolve","process","env","ANDROID_HOME","error","CodeError","ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER","message","stdio","ERR_ANDROID_CANNOT_START_LOGCAT","getApplicationPid","applicationId","output","ERR_ANDROID_CANNOT_GET_APP_PID","pid","parseInt","toString","NaN","isNaN","ERR_ANDROID_UNPROCESSABLE_PID"],"mappings":";;;;;;;;;;AAAA;;AACA;;AACA;;;;AAQO,SAASA,wBAAT,CAAkCC,OAAlC,EAAkE;AACvE,QAAMC,QAAQ,GAAGC,UAAU,CAACF,OAAD,CAA3B;AACA,SAAOG,kBAAkB,CAACF,QAAD,CAAzB;AACD;;AAEM,SAASC,UAAT,CAAoBE,UAApB,EAAiD;AACtD,MAAIA,UAAJ,EAAgB;AACd,WAAOC,cAAKC,OAAL,CAAaF,UAAb,CAAP;AACD;;AAED,SAAOG,OAAO,CAACC,GAAR,CAAYC,YAAZ,GACF,GAAEF,OAAO,CAACC,GAAR,CAAYC,YAAa,qBADzB,GAEH,KAFJ;AAGD;;AAEM,SAASN,kBAAT,CAA4BH,OAA5B,EAA2D;AAChE,MAAI;AACF,qCAAaA,OAAb,EAAsB,CAAC,QAAD,EAAW,IAAX,CAAtB;AACD,GAFD,CAEE,OAAOU,KAAP,EAAc;AACd,UAAM,IAAIC,iBAAJ,CACJC,8CADI,EAEHF,KAAD,CAAiBG,OAFb,CAAN;AAID;;AAED,MAAI;AACF,WAAO,0BAAMb,OAAN,EAAe,CAAC,QAAD,EAAW,IAAX,EAAiB,MAAjB,EAAyB,SAAzB,EAAoC,KAApC,CAAf,EAA2D;AAChEc,MAAAA,KAAK,EAAE;AADyD,KAA3D,CAAP;AAGD,GAJD,CAIE,OAAOJ,KAAP,EAAc;AACd,UAAM,IAAIC,iBAAJ,CACJI,uCADI,EAEHL,KAAD,CAAiBG,OAFb,CAAN;AAID;AACF;;AAEM,SAASG,iBAAT,CACLC,aADK,EAELjB,OAFK,EAGG;AACR,MAAIkB,MAAJ;;AACA,MAAI;AACFA,IAAAA,MAAM,GAAG,iCAAahB,UAAU,CAACF,OAAD,CAAvB,EAAkC,CACzC,OADyC,EAEzC,OAFyC,EAGzC,IAHyC,EAIzCiB,aAJyC,CAAlC,CAAT;AAMD,GAPD,CAOE,OAAOP,KAAP,EAAc;AACd,UAAM,IAAIC,iBAAJ,CACJQ,sCADI,EAEHT,KAAD,CAAiBG,OAFb,CAAN;AAID;;AAED,QAAMO,GAAG,GAAGF,MAAM,GAAGG,QAAQ,CAACH,MAAM,CAACI,QAAP,EAAD,EAAoB,EAApB,CAAX,GAAqCC,GAAvD;;AACA,MAAIC,KAAK,CAACJ,GAAD,CAAT,EAAgB;AACd,UAAM,IAAIT,iBAAJ,CAAcc,qCAAd,CAAN;AACD;;AAED,SAAOL,GAAP;AACD","sourcesContent":["import { spawn, execFileSync, ChildProcess } from 'child_process';\nimport path from 'path';\nimport {\n CodeError,\n ERR_ANDROID_UNPROCESSABLE_PID,\n ERR_ANDROID_CANNOT_GET_APP_PID,\n ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER,\n ERR_ANDROID_CANNOT_START_LOGCAT,\n} from '../errors';\n\nexport function runAndroidLoggingProcess(adbPath?: string): ChildProcess {\n const execPath = getAdbPath(adbPath);\n return spawnLogcatProcess(execPath);\n}\n\nexport function getAdbPath(customPath?: string): string {\n if (customPath) {\n return path.resolve(customPath);\n }\n\n return process.env.ANDROID_HOME\n ? `${process.env.ANDROID_HOME}/platform-tools/adb`\n : 'adb';\n}\n\nexport function spawnLogcatProcess(adbPath: string): ChildProcess {\n try {\n execFileSync(adbPath, ['logcat', '-c']);\n } catch (error) {\n throw new CodeError(\n ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER,\n (error as Error).message\n );\n }\n\n try {\n return spawn(adbPath, ['logcat', '-v', 'time', 'process', 'tag'], {\n stdio: 'pipe',\n });\n } catch (error) {\n throw new CodeError(\n ERR_ANDROID_CANNOT_START_LOGCAT,\n (error as Error).message\n );\n }\n}\n\nexport function getApplicationPid(\n applicationId: string,\n adbPath?: string\n): number {\n let output: Buffer | String | undefined;\n try {\n output = execFileSync(getAdbPath(adbPath), [\n 'shell',\n 'pidof',\n '-s',\n applicationId,\n ]);\n } catch (error) {\n throw new CodeError(\n ERR_ANDROID_CANNOT_GET_APP_PID,\n (error as Error).message\n );\n }\n\n const pid = output ? parseInt(output.toString(), 10) : NaN;\n if (isNaN(pid)) {\n throw new CodeError(ERR_ANDROID_UNPROCESSABLE_PID);\n }\n\n return pid;\n}\n"],"file":"adb.js"}

View File

@@ -0,0 +1,27 @@
declare const codes: {
UNKNOWN: number;
VERBOSE: number;
DEBUG: number;
INFO: number;
WARN: number;
ERROR: number;
FATAL: number;
SILENT: number;
};
export declare type PriorityNames = keyof typeof codes;
export declare const Priority: {
fromName(name: "UNKNOWN" | "VERBOSE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "FATAL" | "SILENT"): number;
toName(code: number): "UNKNOWN" | "VERBOSE" | "DEBUG" | "INFO" | "WARN" | "ERROR" | "FATAL" | "SILENT";
fromLetter(letter: string): number;
toLetter(code: number): string;
UNKNOWN: number;
VERBOSE: number;
DEBUG: number;
INFO: number;
WARN: number;
ERROR: number;
FATAL: number;
SILENT: number;
};
export {};
//# sourceMappingURL=constants.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/android/constants.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,KAAK;;;;;;;;;CASV,CAAC;AAEF,oBAAY,aAAa,GAAG,MAAM,OAAO,KAAK,CAAC;AAE/C,eAAO,MAAM,QAAQ;;;;;;;;;;;;;CAuBpB,CAAC"}

View File

@@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Priority = void 0;
const codes = {
UNKNOWN: 0,
VERBOSE: 1,
DEBUG: 2,
INFO: 3,
WARN: 4,
ERROR: 5,
FATAL: 6,
SILENT: 7
};
const Priority = { ...codes,
fromName(name) {
const value = codes[name.toUpperCase()];
return value ? value : 0;
},
toName(code) {
return Object.keys(codes).find(key => codes[key] === code) || 'UNKNOWN';
},
fromLetter(letter) {
return codes[Object.keys(codes).find(key => key[0] === letter.toUpperCase()) || 'UNKNOWN'];
},
toLetter(code) {
return Priority.toName(code)[0];
}
};
exports.Priority = Priority;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/android/constants.ts"],"names":["codes","UNKNOWN","VERBOSE","DEBUG","INFO","WARN","ERROR","FATAL","SILENT","Priority","fromName","name","value","toUpperCase","toName","code","Object","keys","find","key","fromLetter","letter","toLetter"],"mappings":";;;;;;AAAA,MAAMA,KAAK,GAAG;AACZC,EAAAA,OAAO,EAAE,CADG;AAEZC,EAAAA,OAAO,EAAE,CAFG;AAGZC,EAAAA,KAAK,EAAE,CAHK;AAIZC,EAAAA,IAAI,EAAE,CAJM;AAKZC,EAAAA,IAAI,EAAE,CALM;AAMZC,EAAAA,KAAK,EAAE,CANK;AAOZC,EAAAA,KAAK,EAAE,CAPK;AAQZC,EAAAA,MAAM,EAAE;AARI,CAAd;AAaO,MAAMC,QAAQ,GAAG,EACtB,GAAGT,KADmB;;AAEtBU,EAAAA,QAAQ,CAACC,IAAD,EAA8B;AACpC,UAAMC,KAAK,GAAGZ,KAAK,CAACW,IAAI,CAACE,WAAL,EAAD,CAAnB;AACA,WAAOD,KAAK,GAAGA,KAAH,GAAW,CAAvB;AACD,GALqB;;AAMtBE,EAAAA,MAAM,CAACC,IAAD,EAA8B;AAClC,WACGC,MAAM,CAACC,IAAP,CAAYjB,KAAZ,CAAD,CAAwCkB,IAAxC,CACGC,GAAD,IAAwBnB,KAAK,CAACmB,GAAD,CAAL,KAAeJ,IADzC,KAEK,SAHP;AAKD,GAZqB;;AAatBK,EAAAA,UAAU,CAACC,MAAD,EAAyB;AACjC,WAAOrB,KAAK,CACTgB,MAAM,CAACC,IAAP,CAAYjB,KAAZ,CAAD,CAAwCkB,IAAxC,CACGC,GAAD,IAAwBA,GAAG,CAAC,CAAD,CAAH,KAAWE,MAAM,CAACR,WAAP,EADrC,KAEK,SAHK,CAAZ;AAKD,GAnBqB;;AAoBtBS,EAAAA,QAAQ,CAACP,IAAD,EAAuB;AAC7B,WAAON,QAAQ,CAACK,MAAT,CAAgBC,IAAhB,EAAsB,CAAtB,CAAP;AACD;;AAtBqB,CAAjB","sourcesContent":["const codes = {\n UNKNOWN: 0,\n VERBOSE: 1,\n DEBUG: 2,\n INFO: 3,\n WARN: 4,\n ERROR: 5,\n FATAL: 6,\n SILENT: 7,\n};\n\nexport type PriorityNames = keyof typeof codes;\n\nexport const Priority = {\n ...codes,\n fromName(name: PriorityNames): number {\n const value = codes[name.toUpperCase() as PriorityNames];\n return value ? value : 0;\n },\n toName(code: number): PriorityNames {\n return (\n (Object.keys(codes) as PriorityNames[]).find(\n (key: PriorityNames) => codes[key] === code\n ) || 'UNKNOWN'\n );\n },\n fromLetter(letter: string): number {\n return codes[\n (Object.keys(codes) as PriorityNames[]).find(\n (key: PriorityNames) => key[0] === letter.toUpperCase()\n ) || 'UNKNOWN'\n ];\n },\n toLetter(code: number): string {\n return Priority.toName(code)[0];\n },\n};\n"],"file":"constants.js"}

View File

@@ -0,0 +1,20 @@
/// <reference types="node" />
import { EventEmitter } from 'events';
import { IFilter, Platform } from './types';
export { Priority as AndroidPriority } from './android/constants';
export { Priority as IosPriority } from './ios/constants';
export { formatEntry, formatError } from './formatters';
export { Entry } from './types';
export declare type LogkittyOptions = {
platform: Platform;
adbPath?: string;
priority?: number;
filter?: FilterCreator;
};
export declare type FilterCreator = (platform: Platform, minPriority?: number, adbPath?: string) => IFilter;
export declare function makeTagsFilter(...tags: string[]): FilterCreator;
export declare function makeAppFilter(appIdentifier: string): FilterCreator;
export declare function makeMatchFilter(...regexes: RegExp[]): FilterCreator;
export declare function makeCustomFilter(...patterns: string[]): FilterCreator;
export declare function logkitty(options: LogkittyOptions): EventEmitter;
//# sourceMappingURL=api.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,OAAO,EAAS,QAAQ,EAAE,MAAM,SAAS,CAAC;AAMnD,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAOlE,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,oBAAY,eAAe,GAAG;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,oBAAY,aAAa,GAAG,CAC1B,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC;AAEb,wBAAgB,cAAc,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAS/D;AAED,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,CAUlE;AAED,wBAAgB,eAAe,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,aAAa,CASnE;AAED,wBAAgB,gBAAgB,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,aAAa,CAUrE;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,YAAY,CAwE/D"}

View File

@@ -0,0 +1,174 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.makeTagsFilter = makeTagsFilter;
exports.makeAppFilter = makeAppFilter;
exports.makeMatchFilter = makeMatchFilter;
exports.makeCustomFilter = makeCustomFilter;
exports.logkitty = logkitty;
Object.defineProperty(exports, "Entry", {
enumerable: true,
get: function () {
return _types.Entry;
}
});
Object.defineProperty(exports, "AndroidPriority", {
enumerable: true,
get: function () {
return _constants.Priority;
}
});
Object.defineProperty(exports, "IosPriority", {
enumerable: true,
get: function () {
return _constants2.Priority;
}
});
Object.defineProperty(exports, "formatEntry", {
enumerable: true,
get: function () {
return _formatters.formatEntry;
}
});
Object.defineProperty(exports, "formatError", {
enumerable: true,
get: function () {
return _formatters.formatError;
}
});
var _events = require("events");
var _types = require("./types");
var _AndroidFilter = _interopRequireDefault(require("./android/AndroidFilter"));
var _AndroidParser = _interopRequireDefault(require("./android/AndroidParser"));
var _adb = require("./android/adb");
var _constants = require("./android/constants");
var _IosParser = _interopRequireDefault(require("./ios/IosParser"));
var _IosFilter = _interopRequireDefault(require("./ios/IosFilter"));
var _simulator = require("./ios/simulator");
var _errors = require("./errors");
var _constants2 = require("./ios/constants");
var _formatters = require("./formatters");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* Common */
/* Android */
/* iOS */
/* Exports */
function makeTagsFilter(...tags) {
return (platform, minPriority) => {
const filter = platform === 'android' ? new _AndroidFilter.default(minPriority) : new _IosFilter.default(minPriority);
filter.setFilterByTag(tags);
return filter;
};
}
function makeAppFilter(appIdentifier) {
return (platform, minPriority, adbPath) => {
if (platform !== 'android') {
throw new Error('App filter is only available for Android');
}
const filter = new _AndroidFilter.default(minPriority);
filter.setFilterByApp(appIdentifier, adbPath);
return filter;
};
}
function makeMatchFilter(...regexes) {
return (platform, minPriority) => {
const filter = platform === 'android' ? new _AndroidFilter.default(minPriority) : new _IosFilter.default(minPriority);
filter.setFilterByMatch(regexes);
return filter;
};
}
function makeCustomFilter(...patterns) {
return (platform, minPriority) => {
if (platform !== 'android') {
throw new Error('Custom filter is only available for Android');
}
const filter = new _AndroidFilter.default(minPriority);
filter.setCustomFilter(patterns);
return filter;
};
}
function logkitty(options) {
const {
platform,
adbPath,
priority,
filter: createFilter
} = options;
const emitter = new _events.EventEmitter();
if (!['ios', 'android'].some(availablePlatform => availablePlatform === platform)) {
throw new Error(`Platform ${platform} is not supported`);
}
const parser = platform === 'android' ? new _AndroidParser.default() : new _IosParser.default();
let filter;
if (createFilter) {
filter = createFilter(platform, priority, adbPath);
} else {
filter = platform === 'android' ? new _AndroidFilter.default(priority) : new _IosFilter.default(priority);
}
const loggingProcess = platform === 'android' ? (0, _adb.runAndroidLoggingProcess)(adbPath) : (0, _simulator.runSimulatorLoggingProcess)();
process.on('exit', () => {
loggingProcess.kill();
emitter.emit('exit');
});
loggingProcess.stderr.on('data', errorData => {
if (platform === 'ios' && errorData.toString().includes('No devices are booted.')) {
emitter.emit('error', new _errors.CodeError(_errors.ERR_IOS_NO_SIMULATORS_BOOTED, 'No simulators are booted.'));
} else {
emitter.emit('error', new Error(errorData.toString()));
}
});
loggingProcess.stdout.on('data', raw => {
let entryToLog;
try {
const messages = parser.splitMessages(raw.toString());
const entries = parser.parseMessages(messages);
entries.forEach(entry => {
if (filter.shouldInclude(entry)) {
entryToLog = entry;
}
});
} catch (error) {
emitter.emit('error', error);
}
if (entryToLog) {
emitter.emit('entry', entryToLog);
}
});
loggingProcess.stdout.on('error', error => {
emitter.emit('error', error);
emitter.emit('exit');
});
return emitter;
}
//# sourceMappingURL=api.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=cli.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,156 @@
"use strict";
var _yargs = _interopRequireDefault(require("yargs"));
var _api = require("./api");
var _formatters = require("./formatters");
var _utils = require("./utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const androidPriorityOptions = {
unknown: {
alias: ['U', 'u'],
boolean: true,
default: false,
describe: 'Unknown priority'
},
verbose: {
alias: ['V', 'v'],
boolean: true,
default: false,
describe: 'Verbose priority'
},
debug: {
alias: ['D', 'd'],
boolean: true,
default: false,
describe: 'Debug priority'
},
info: {
alias: ['I', 'i'],
boolean: true,
default: false,
describe: 'Info priority'
},
warn: {
alias: ['W', 'w'],
boolean: true,
default: false,
describe: 'Warn priority'
},
error: {
alias: ['E', 'e'],
boolean: true,
default: false,
describe: 'Error priority'
},
fatal: {
alias: ['F', 'f'],
boolean: true,
default: false,
describe: 'Fatal priority'
},
silent: {
alias: ['S', 's'],
boolean: true,
default: false,
describe: 'Silent priority'
}
};
const iosPriorityOptions = {
debug: {
alias: ['D', 'd'],
boolean: true,
default: false,
describe: 'Debug level'
},
info: {
alias: ['I', 'i'],
boolean: true,
default: false,
describe: 'Info level'
},
error: {
alias: ['E', 'e'],
boolean: true,
default: false,
describe: 'Error level'
}
};
const {
argv: {
_: [platform, filter],
...args
}
} = _yargs.default.usage('Usage: $0 [options] <platform>').command('android', 'Android', yargs => yargs.command('tag <tags ...>', 'Show logs matching given tags', androidPriorityOptions).command('app <appId>', 'Show logs from application with given identifier', androidPriorityOptions).command('match <regexes...>', 'Show logs matching given patterns', androidPriorityOptions).command('custom <patterns ...>', 'Filter using custom patterns <tag>:<priority>').command('all', 'Show all logs', androidPriorityOptions).demandCommand(1).option('adb-path', {
type: 'string',
describe: 'Use custom path to adb',
nargs: 1
}).example('$0 android tag MyTag', 'Filter logs to only include ones with MyTag tag').example('$0 android tag MyTag -I', 'Filter logs to only include ones with MyTag tag and priority INFO and above').example('$0 android app com.example.myApp', 'Show all logs from com.example.myApp').example('$0 android match device', 'Show all logs matching /device/gm regex').example('$0 android app com.example.myApp -E', 'Show all logs from com.example.myApp with priority ERROR and above').example('$0 android custom *:S MyTag:D', 'Silence all logs and show only ones with MyTag with priority DEBUG and above')).command('ios <filter>', 'iOS', yargs => yargs.command('tag <tags ...>', 'Show logs matching given tags', iosPriorityOptions).command('match <regexes...>', 'Show logs matching given patterns', iosPriorityOptions).command('all', 'Show all logs', iosPriorityOptions).demandCommand(1).example('$0 ios tag MyTag', 'Filter logs to only include ones with MyTag tag').example('$0 ios tag MyTag -i', 'Filter logs to only include ones with MyTag tag and priority Info and Error').example('$0 ios match device', 'Show all logs matching /device/gm regex')).demandCommand(1).help('h').alias('h', 'help').alias('v', 'version').version();
const selectedAndroidPriorities = {
unknown: Boolean(args.unknown),
verbose: Boolean(args.verbose),
debug: Boolean(args.debug),
info: Boolean(args.info),
warn: Boolean(args.warn),
error: Boolean(args.error),
fatal: Boolean(args.fatal),
silent: Boolean(args.silent)
};
const selectedIosPriorities = {
debug: Boolean(args.debug),
info: Boolean(args.info),
error: Boolean(args.error)
};
try {
let createFilter;
switch (filter) {
case 'app':
createFilter = (0, _api.makeAppFilter)(args.appId);
break;
case 'tag':
createFilter = (0, _api.makeTagsFilter)(...args.tags);
break;
case 'match':
createFilter = (0, _api.makeMatchFilter)(...args.regexes.map(value => new RegExp(value, 'gm')));
break;
case 'custom':
createFilter = (0, _api.makeCustomFilter)(...args.patterns);
break;
case 'all':
default:
}
const emitter = (0, _api.logkitty)({
platform: platform,
adbPath: args.adbPath ? String(args.adbPath) : '',
priority: platform === 'android' ? (0, _utils.getMinPriority)(_api.AndroidPriority, selectedAndroidPriorities, _api.AndroidPriority.DEBUG) : (0, _utils.getMinPriority)(_api.IosPriority, selectedIosPriorities, _api.IosPriority.DEFAULT),
filter: createFilter
});
emitter.on('entry', entry => {
process.stdout.write((0, _formatters.formatEntry)(entry));
});
emitter.on('error', error => {
terminate(error);
});
} catch (error) {
terminate(error);
}
function terminate(error) {
// eslint-disable-next-line no-console
console.log((0, _formatters.formatError)(error));
process.exit(1);
}
//# sourceMappingURL=cli.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
export declare class CodeError extends Error {
code: string;
constructor(code: string, message?: string);
}
export declare const ERR_ANDROID_UNPROCESSABLE_PID = "ERR_ANDROID_UNPROCESSABLE_PID";
export declare const ERR_ANDROID_CANNOT_GET_APP_PID = "ERR_ANDROID_CANNOT_GET_APP_PID";
export declare const ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER = "ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER";
export declare const ERR_ANDROID_CANNOT_START_LOGCAT = "ERR_ANDROID_CANNOT_START_LOGCAT";
export declare const ERR_IOS_CANNOT_LIST_SIMULATORS = "ERR_IOS_CANNOT_LIST_SIMULATORS";
export declare const ERR_IOS_NO_SIMULATORS_BOOTED = "ERR_IOS_NO_SIMULATORS_BOOTED";
export declare const ERR_IOS_CANNOT_START_SYSLOG = "ERR_IOS_CANNOT_START_SYSLOG";
//# sourceMappingURL=errors.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;IAClC,IAAI,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAI3C;AAED,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAC7E,eAAO,MAAM,8BAA8B,mCAAmC,CAAC;AAC/E,eAAO,MAAM,sCAAsC,2CACT,CAAC;AAC3C,eAAO,MAAM,+BAA+B,oCACT,CAAC;AAEpC,eAAO,MAAM,8BAA8B,mCAAmC,CAAC;AAC/E,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAC3E,eAAO,MAAM,2BAA2B,gCAAgC,CAAC"}

View File

@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ERR_IOS_CANNOT_START_SYSLOG = exports.ERR_IOS_NO_SIMULATORS_BOOTED = exports.ERR_IOS_CANNOT_LIST_SIMULATORS = exports.ERR_ANDROID_CANNOT_START_LOGCAT = exports.ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER = exports.ERR_ANDROID_CANNOT_GET_APP_PID = exports.ERR_ANDROID_UNPROCESSABLE_PID = exports.CodeError = void 0;
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class CodeError extends Error {
constructor(code, message) {
super(message);
_defineProperty(this, "code", void 0);
this.code = code;
}
}
exports.CodeError = CodeError;
const ERR_ANDROID_UNPROCESSABLE_PID = 'ERR_ANDROID_UNPROCESSABLE_PID';
exports.ERR_ANDROID_UNPROCESSABLE_PID = ERR_ANDROID_UNPROCESSABLE_PID;
const ERR_ANDROID_CANNOT_GET_APP_PID = 'ERR_ANDROID_CANNOT_GET_APP_PID';
exports.ERR_ANDROID_CANNOT_GET_APP_PID = ERR_ANDROID_CANNOT_GET_APP_PID;
const ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER = 'ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER';
exports.ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER = ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER;
const ERR_ANDROID_CANNOT_START_LOGCAT = 'ERR_ANDROID_CANNOT_START_LOGCAT';
exports.ERR_ANDROID_CANNOT_START_LOGCAT = ERR_ANDROID_CANNOT_START_LOGCAT;
const ERR_IOS_CANNOT_LIST_SIMULATORS = 'ERR_IOS_CANNOT_LIST_SIMULATORS';
exports.ERR_IOS_CANNOT_LIST_SIMULATORS = ERR_IOS_CANNOT_LIST_SIMULATORS;
const ERR_IOS_NO_SIMULATORS_BOOTED = 'ERR_IOS_NO_SIMULATORS_BOOTED';
exports.ERR_IOS_NO_SIMULATORS_BOOTED = ERR_IOS_NO_SIMULATORS_BOOTED;
const ERR_IOS_CANNOT_START_SYSLOG = 'ERR_IOS_CANNOT_START_SYSLOG';
exports.ERR_IOS_CANNOT_START_SYSLOG = ERR_IOS_CANNOT_START_SYSLOG;
//# sourceMappingURL=errors.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/errors.ts"],"names":["CodeError","Error","constructor","code","message","ERR_ANDROID_UNPROCESSABLE_PID","ERR_ANDROID_CANNOT_GET_APP_PID","ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER","ERR_ANDROID_CANNOT_START_LOGCAT","ERR_IOS_CANNOT_LIST_SIMULATORS","ERR_IOS_NO_SIMULATORS_BOOTED","ERR_IOS_CANNOT_START_SYSLOG"],"mappings":";;;;;;;;;AAAO,MAAMA,SAAN,SAAwBC,KAAxB,CAA8B;AAGnCC,EAAAA,WAAW,CAACC,IAAD,EAAeC,OAAf,EAAiC;AAC1C,UAAMA,OAAN;;AAD0C;;AAE1C,SAAKD,IAAL,GAAYA,IAAZ;AACD;;AANkC;;;AAS9B,MAAME,6BAA6B,GAAG,+BAAtC;;AACA,MAAMC,8BAA8B,GAAG,gCAAvC;;AACA,MAAMC,sCAAsC,GACjD,wCADK;;AAEA,MAAMC,+BAA+B,GAC1C,iCADK;;AAGA,MAAMC,8BAA8B,GAAG,gCAAvC;;AACA,MAAMC,4BAA4B,GAAG,8BAArC;;AACA,MAAMC,2BAA2B,GAAG,6BAApC","sourcesContent":["export class CodeError extends Error {\n code: string;\n\n constructor(code: string, message?: string) {\n super(message);\n this.code = code;\n }\n}\n\nexport const ERR_ANDROID_UNPROCESSABLE_PID = 'ERR_ANDROID_UNPROCESSABLE_PID';\nexport const ERR_ANDROID_CANNOT_GET_APP_PID = 'ERR_ANDROID_CANNOT_GET_APP_PID';\nexport const ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER =\n 'ERR_ANDROID_CANNOT_CLEAN_LOGCAT_BUFFER';\nexport const ERR_ANDROID_CANNOT_START_LOGCAT =\n 'ERR_ANDROID_CANNOT_START_LOGCAT';\n\nexport const ERR_IOS_CANNOT_LIST_SIMULATORS = 'ERR_IOS_CANNOT_LIST_SIMULATORS';\nexport const ERR_IOS_NO_SIMULATORS_BOOTED = 'ERR_IOS_NO_SIMULATORS_BOOTED';\nexport const ERR_IOS_CANNOT_START_SYSLOG = 'ERR_IOS_CANNOT_START_SYSLOG';\n"],"file":"errors.js"}

View File

@@ -0,0 +1,5 @@
import { CodeError } from './errors';
import { Entry } from './types';
export declare function formatError(error: CodeError | Error): string;
export declare function formatEntry(entry: Entry): string;
//# sourceMappingURL=formatters.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGrC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,CAU5D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAyEhD"}

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.formatError = formatError;
exports.formatEntry = formatEntry;
var _ansiFragments = require("ansi-fragments");
var _constants = require("./android/constants");
var _constants2 = require("./ios/constants");
function formatError(error) {
return (0, _ansiFragments.container)((0, _ansiFragments.color)('red', '✖︎ Ups, something went wrong'), (0, _ansiFragments.pad)(2, '\n'), (0, _ansiFragments.color)('red', (0, _ansiFragments.modifier)('bold', 'CODE'), ' ▶︎ '), 'code' in error ? error.code : 'ERR_UNKNOWN', (0, _ansiFragments.pad)(1, '\n'), (0, _ansiFragments.color)('red', (0, _ansiFragments.modifier)('bold', 'MESSAGE'), ' ▶︎ '), error.message).build();
}
function formatEntry(entry) {
let priorityColor = 'none';
let priorityModifier = 'none';
if (entry.platform === 'android' && entry.priority >= _constants.Priority.ERROR || entry.platform === 'ios' && entry.priority >= _constants2.Priority.ERROR) {
priorityColor = 'red';
} else if (entry.platform === 'android' && entry.priority === _constants.Priority.WARN) {
priorityColor = 'yellow';
} else if (entry.platform === 'android' && entry.priority === _constants.Priority.VERBOSE || entry.platform === 'ios' && entry.priority === _constants2.Priority.DEBUG) {
priorityModifier = 'dim';
}
const output = (0, _ansiFragments.container)((0, _ansiFragments.modifier)('dim', `[${entry.date.format('HH:mm:ss')}]`), (0, _ansiFragments.pad)(1), (0, _ansiFragments.color)(priorityColor, (0, _ansiFragments.modifier)(priorityModifier, `${entry.platform === 'android' ? _constants.Priority.toLetter(entry.priority) : _constants2.Priority.toLetter(entry.priority)} |`)), (0, _ansiFragments.pad)(1), (0, _ansiFragments.modifier)('bold', (0, _ansiFragments.color)(priorityColor, (0, _ansiFragments.modifier)(priorityModifier, entry.tag || entry.appId || ''))), (0, _ansiFragments.pad)(1), (0, _ansiFragments.color)(priorityColor, (0, _ansiFragments.modifier)(priorityModifier, '▶︎')), (0, _ansiFragments.pad)(1), (0, _ansiFragments.color)(priorityColor, (0, _ansiFragments.modifier)(priorityModifier, entry.messages[0])), (0, _ansiFragments.ifElse)(entry.messages.length > 1, (0, _ansiFragments.container)(...entry.messages.slice(1).map((line, index, arr) => (0, _ansiFragments.container)((0, _ansiFragments.pad)(1, '\n'), (0, _ansiFragments.pad)((entry.tag || entry.appId || '').length + 16), (0, _ansiFragments.color)(priorityColor, (0, _ansiFragments.modifier)(priorityColor === 'none' ? 'dim' : 'none', `${index === arr.length - 1 ? '└' : '│'} `)), (0, _ansiFragments.color)(priorityColor, (0, _ansiFragments.modifier)(priorityModifier, line))))), '')).build();
return `${output}\n`;
}
//# sourceMappingURL=formatters.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
import { IFilter, Entry } from '../types';
export default class IosFilter implements IFilter {
private readonly minPriority;
private filter;
constructor(minPriority?: number);
setFilterByTag(tags: string[]): void;
setFilterByMatch(regexes: RegExp[]): void;
shouldInclude(entry: Entry): boolean;
}
//# sourceMappingURL=IosFilter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IosFilter.d.ts","sourceRoot":"","sources":["../../src/ios/IosFilter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAI1C,MAAM,CAAC,OAAO,OAAO,SAAU,YAAW,OAAO;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,MAAM,CAAS;gBAEX,WAAW,GAAE,MAAU;IAQnC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE;IAU7B,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE;IAalC,aAAa,CAAC,KAAK,EAAE,KAAK;CAG3B"}

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class IosFilter {
constructor(minPriority = 0) {
_defineProperty(this, "minPriority", void 0);
_defineProperty(this, "filter", void 0);
this.minPriority = minPriority; // Default filter by all
this.filter = entry => {
return entry.priority >= this.minPriority;
};
}
setFilterByTag(tags) {
this.filter = entry => {
return Boolean(entry.priority >= this.minPriority && entry.tag && tags.indexOf(entry.tag) > -1);
};
}
setFilterByMatch(regexes) {
this.filter = entry => {
return entry.priority >= this.minPriority && Boolean(regexes.find(reg => Boolean(entry.messages.find(message => reg.test(message)))));
};
}
shouldInclude(entry) {
return this.filter(entry);
}
}
exports.default = IosFilter;
//# sourceMappingURL=IosFilter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/ios/IosFilter.ts"],"names":["IosFilter","constructor","minPriority","filter","entry","priority","setFilterByTag","tags","Boolean","tag","indexOf","setFilterByMatch","regexes","find","reg","messages","message","test","shouldInclude"],"mappings":";;;;;;;;;AAIe,MAAMA,SAAN,CAAmC;AAIhDC,EAAAA,WAAW,CAACC,WAAmB,GAAG,CAAvB,EAA0B;AAAA;;AAAA;;AACnC,SAAKA,WAAL,GAAmBA,WAAnB,CADmC,CAEnC;;AACA,SAAKC,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aAAOA,KAAK,CAACC,QAAN,IAAkB,KAAKH,WAA9B;AACD,KAFD;AAGD;;AAEDI,EAAAA,cAAc,CAACC,IAAD,EAAiB;AAC7B,SAAKJ,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aAAOI,OAAO,CACZJ,KAAK,CAACC,QAAN,IAAkB,KAAKH,WAAvB,IACEE,KAAK,CAACK,GADR,IAEEF,IAAI,CAACG,OAAL,CAAaN,KAAK,CAACK,GAAnB,IAA0B,CAAC,CAHjB,CAAd;AAKD,KAND;AAOD;;AAEDE,EAAAA,gBAAgB,CAACC,OAAD,EAAoB;AAClC,SAAKT,MAAL,GAAeC,KAAD,IAAkB;AAC9B,aACEA,KAAK,CAACC,QAAN,IAAkB,KAAKH,WAAvB,IACAM,OAAO,CACLI,OAAO,CAACC,IAAR,CAAcC,GAAD,IACXN,OAAO,CAACJ,KAAK,CAACW,QAAN,CAAeF,IAAf,CAAqBG,OAAD,IAAqBF,GAAG,CAACG,IAAJ,CAASD,OAAT,CAAzC,CAAD,CADT,CADK,CAFT;AAQD,KATD;AAUD;;AAEDE,EAAAA,aAAa,CAACd,KAAD,EAAe;AAC1B,WAAO,KAAKD,MAAL,CAAYC,KAAZ,CAAP;AACD;;AArC+C","sourcesContent":["import { IFilter, Entry } from '../types';\n\ntype Filter = (entry: Entry) => boolean;\n\nexport default class IosFilter implements IFilter {\n private readonly minPriority: number;\n private filter: Filter;\n\n constructor(minPriority: number = 0) {\n this.minPriority = minPriority;\n // Default filter by all\n this.filter = (entry: Entry) => {\n return entry.priority >= this.minPriority;\n };\n }\n\n setFilterByTag(tags: string[]) {\n this.filter = (entry: Entry) => {\n return Boolean(\n entry.priority >= this.minPriority &&\n entry.tag &&\n tags.indexOf(entry.tag) > -1\n );\n };\n }\n\n setFilterByMatch(regexes: RegExp[]) {\n this.filter = (entry: Entry) => {\n return (\n entry.priority >= this.minPriority &&\n Boolean(\n regexes.find((reg: RegExp) =>\n Boolean(entry.messages.find((message: string) => reg.test(message)))\n )\n )\n );\n };\n }\n\n shouldInclude(entry: Entry) {\n return this.filter(entry);\n }\n}\n"],"file":"IosFilter.js"}

View File

@@ -0,0 +1,8 @@
import { IParser, Entry } from '../types';
export default class IosParser implements IParser {
static timeRegex: RegExp;
static headerRegex: RegExp;
splitMessages(raw: string): string[];
parseMessages(messages: string[]): Entry[];
}
//# sourceMappingURL=IosParser.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"IosParser.d.ts","sourceRoot":"","sources":["../../src/ios/IosParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,CAAC,OAAO,OAAO,SAAU,YAAW,OAAO;IAC/C,MAAM,CAAC,SAAS,EAAE,MAAM,CAAmD;IAC3E,MAAM,CAAC,WAAW,EAAE,MAAM,CAAgE;IAE1F,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE;IAepC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE;CA0C3C"}

View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _dayjs = _interopRequireDefault(require("dayjs"));
var _constants = require("./constants");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class IosParser {
splitMessages(raw) {
const messages = [];
let data = raw.toString();
let match = data.match(IosParser.timeRegex);
while (match) {
const timeMatch = match[0];
data = data.slice((match.index || 0) + timeMatch.length);
const nextMatch = data.match(IosParser.timeRegex);
const body = nextMatch ? data.slice(0, nextMatch.index) : data;
messages.push(`${timeMatch} ${body}`);
match = nextMatch;
}
return messages;
}
parseMessages(messages) {
return messages.map(rawMessage => {
const timeMatch = rawMessage.match(IosParser.timeRegex);
if (!timeMatch) {
throw new Error(`Time regex was not matched in message: ${rawMessage}`);
}
const headerMatch = rawMessage.slice(timeMatch[0].length).match(IosParser.headerRegex) || ['', 'Default', '-1', 'unknown'];
const [, priority, pid, tag] = headerMatch;
return {
platform: 'ios',
date: (0, _dayjs.default)(timeMatch[0]).set('millisecond', 0),
pid: parseInt(pid.trim(), 10) || 0,
priority: _constants.Priority.fromName(priority),
tag,
messages: [rawMessage.slice(timeMatch[0].length + headerMatch[0].length).trim()]
};
}).reduce((acc, entry) => {
if (acc.length > 0 && acc[acc.length - 1].date.isSame(entry.date) && acc[acc.length - 1].appId === entry.appId && acc[acc.length - 1].pid === entry.pid && acc[acc.length - 1].priority === entry.priority) {
acc[acc.length - 1].messages.push(...entry.messages);
return acc;
}
return [...acc, entry];
}, []);
}
}
exports.default = IosParser;
_defineProperty(IosParser, "timeRegex", /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\.[\d+]+/m);
_defineProperty(IosParser, "headerRegex", /^\s+[a-z0-9]+\s+(\w+)\s+[a-z0-9]+\s+(\d+)\s+\d+\s+([^:]+):/);
//# sourceMappingURL=IosParser.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,19 @@
declare const codes: {
DEBUG: number;
DEFAULT: number;
INFO: number;
ERROR: number;
};
export declare type PriorityNames = keyof typeof codes;
export declare const Priority: {
fromName(name: "DEBUG" | "INFO" | "ERROR" | "DEFAULT"): number;
toName(code: number): "DEBUG" | "INFO" | "ERROR" | "DEFAULT";
fromLetter(letter: string): number;
toLetter(code: number): string;
DEBUG: number;
DEFAULT: number;
INFO: number;
ERROR: number;
};
export {};
//# sourceMappingURL=constants.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/ios/constants.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,KAAK;;;;;CAKV,CAAC;AAEF,oBAAY,aAAa,GAAG,MAAM,OAAO,KAAK,CAAC;AAE/C,eAAO,MAAM,QAAQ;;;;;;;;;CAuBpB,CAAC"}

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Priority = void 0;
const codes = {
DEBUG: 0,
DEFAULT: 1,
INFO: 2,
ERROR: 3
};
const Priority = { ...codes,
fromName(name) {
const value = codes[name.toUpperCase()];
return value ? value : 0;
},
toName(code) {
return Object.keys(codes).find(key => codes[key] === code) || 'DEFAULT';
},
fromLetter(letter) {
return codes[Object.keys(codes).find(key => key[0] === letter.toUpperCase()) || 'DEFAULT'];
},
toLetter(code) {
return Priority.toName(code)[0];
}
};
exports.Priority = Priority;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/ios/constants.ts"],"names":["codes","DEBUG","DEFAULT","INFO","ERROR","Priority","fromName","name","value","toUpperCase","toName","code","Object","keys","find","key","fromLetter","letter","toLetter"],"mappings":";;;;;;AAAA,MAAMA,KAAK,GAAG;AACZC,EAAAA,KAAK,EAAE,CADK;AAEZC,EAAAA,OAAO,EAAE,CAFG;AAGZC,EAAAA,IAAI,EAAE,CAHM;AAIZC,EAAAA,KAAK,EAAE;AAJK,CAAd;AASO,MAAMC,QAAQ,GAAG,EACtB,GAAGL,KADmB;;AAEtBM,EAAAA,QAAQ,CAACC,IAAD,EAA8B;AACpC,UAAMC,KAAK,GAAGR,KAAK,CAACO,IAAI,CAACE,WAAL,EAAD,CAAnB;AACA,WAAOD,KAAK,GAAGA,KAAH,GAAW,CAAvB;AACD,GALqB;;AAMtBE,EAAAA,MAAM,CAACC,IAAD,EAA8B;AAClC,WACGC,MAAM,CAACC,IAAP,CAAYb,KAAZ,CAAD,CAAwCc,IAAxC,CACGC,GAAD,IAAwBf,KAAK,CAACe,GAAD,CAAL,KAAeJ,IADzC,KAEK,SAHP;AAKD,GAZqB;;AAatBK,EAAAA,UAAU,CAACC,MAAD,EAAyB;AACjC,WAAOjB,KAAK,CACTY,MAAM,CAACC,IAAP,CAAYb,KAAZ,CAAD,CAAwCc,IAAxC,CACGC,GAAD,IAAwBA,GAAG,CAAC,CAAD,CAAH,KAAWE,MAAM,CAACR,WAAP,EADrC,KAEK,SAHK,CAAZ;AAKD,GAnBqB;;AAoBtBS,EAAAA,QAAQ,CAACP,IAAD,EAAuB;AAC7B,WAAON,QAAQ,CAACK,MAAT,CAAgBC,IAAhB,EAAsB,CAAtB,CAAP;AACD;;AAtBqB,CAAjB","sourcesContent":["const codes = {\n DEBUG: 0,\n DEFAULT: 1,\n INFO: 2,\n ERROR: 3,\n};\n\nexport type PriorityNames = keyof typeof codes;\n\nexport const Priority = {\n ...codes,\n fromName(name: PriorityNames): number {\n const value = codes[name.toUpperCase() as PriorityNames];\n return value ? value : 0;\n },\n toName(code: number): PriorityNames {\n return (\n (Object.keys(codes) as PriorityNames[]).find(\n (key: PriorityNames) => codes[key] === code\n ) || 'DEFAULT'\n );\n },\n fromLetter(letter: string): number {\n return codes[\n (Object.keys(codes) as PriorityNames[]).find(\n (key: PriorityNames) => key[0] === letter.toUpperCase()\n ) || 'DEFAULT'\n ];\n },\n toLetter(code: number): string {\n return Priority.toName(code)[0];\n },\n};\n"],"file":"constants.js"}

View File

@@ -0,0 +1,4 @@
/// <reference types="node" />
import { ChildProcess } from 'child_process';
export declare function runSimulatorLoggingProcess(): ChildProcess;
//# sourceMappingURL=simulator.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"simulator.d.ts","sourceRoot":"","sources":["../../src/ios/simulator.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAS,MAAM,eAAe,CAAC;AAGpD,wBAAgB,0BAA0B,IAAI,YAAY,CAsBzD"}

View File

@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.runSimulatorLoggingProcess = runSimulatorLoggingProcess;
var _child_process = require("child_process");
var _errors = require("../errors");
function runSimulatorLoggingProcess() {
try {
return (0, _child_process.spawn)('xcrun', ['simctl', 'spawn', 'booted', 'log', 'stream', '--type', 'log', '--level', 'debug'], {
stdio: 'pipe'
});
} catch (error) {
throw new _errors.CodeError(_errors.ERR_IOS_CANNOT_START_SYSLOG, error.message);
}
}
//# sourceMappingURL=simulator.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/ios/simulator.ts"],"names":["runSimulatorLoggingProcess","stdio","error","CodeError","ERR_IOS_CANNOT_START_SYSLOG","message"],"mappings":";;;;;;;AAAA;;AACA;;AAEO,SAASA,0BAAT,GAAoD;AACzD,MAAI;AACF,WAAO,0BACL,OADK,EAEL,CACE,QADF,EAEE,OAFF,EAGE,QAHF,EAIE,KAJF,EAKE,QALF,EAME,QANF,EAOE,KAPF,EAQE,SARF,EASE,OATF,CAFK,EAaL;AACEC,MAAAA,KAAK,EAAE;AADT,KAbK,CAAP;AAiBD,GAlBD,CAkBE,OAAOC,KAAP,EAAc;AACd,UAAM,IAAIC,iBAAJ,CAAcC,mCAAd,EAA4CF,KAAD,CAAiBG,OAA5D,CAAN;AACD;AACF","sourcesContent":["import { ChildProcess, spawn } from 'child_process';\nimport { CodeError, ERR_IOS_CANNOT_START_SYSLOG } from '../errors';\n\nexport function runSimulatorLoggingProcess(): ChildProcess {\n try {\n return spawn(\n 'xcrun',\n [\n 'simctl',\n 'spawn',\n 'booted',\n 'log',\n 'stream',\n '--type',\n 'log',\n '--level',\n 'debug',\n ],\n {\n stdio: 'pipe',\n }\n );\n } catch (error) {\n throw new CodeError(ERR_IOS_CANNOT_START_SYSLOG, (error as Error).message);\n }\n}\n"],"file":"simulator.js"}

View File

@@ -0,0 +1,19 @@
import { Dayjs } from 'dayjs';
export declare type Platform = 'ios' | 'android';
export declare type Entry = {
date: Dayjs;
pid: number;
priority: number;
tag?: string;
appId?: string;
messages: string[];
platform: Platform;
};
export interface IParser {
splitMessages(data: string): string[];
parseMessages(messages: string[]): Entry[];
}
export interface IFilter {
shouldInclude(entry: Entry): boolean;
}
//# sourceMappingURL=types.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,oBAAY,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;AAEzC,oBAAY,KAAK,GAAG;IAClB,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,MAAM,WAAW,OAAO;IACtB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACtC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,OAAO;IACtB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC;CACtC"}

View File

@@ -0,0 +1,2 @@
"use strict";
//# sourceMappingURL=types.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","sourcesContent":[],"file":"types.js"}

View File

@@ -0,0 +1,6 @@
export declare function getMinPriority(Priority: {
fromName: (key: any) => number;
}, priorities: {
[key: string]: boolean;
}, defaultPriority: number): number;
//# sourceMappingURL=utils.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAC5B,QAAQ,EAAE;IAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAA;CAAE,EAC5C,UAAU,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EACtC,eAAe,EAAE,MAAM,GACtB,MAAM,CASR"}

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getMinPriority = getMinPriority;
function getMinPriority(Priority, priorities, defaultPriority) {
const parsedPriorities = Object.keys(priorities).filter(key => priorities[key]).map(key => {
return Priority.fromName(key);
});
return parsedPriorities.length ? Math.min(...parsedPriorities) : defaultPriority;
}
//# sourceMappingURL=utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/utils.ts"],"names":["getMinPriority","Priority","priorities","defaultPriority","parsedPriorities","Object","keys","filter","key","map","fromName","length","Math","min"],"mappings":";;;;;;;AAAO,SAASA,cAAT,CACLC,QADK,EAELC,UAFK,EAGLC,eAHK,EAIG;AACR,QAAMC,gBAAgB,GAAGC,MAAM,CAACC,IAAP,CAAYJ,UAAZ,EACtBK,MADsB,CACdC,GAAD,IAAiBN,UAAU,CAACM,GAAD,CADZ,EAEtBC,GAFsB,CAEjBD,GAAD,IAAiB;AACpB,WAAOP,QAAQ,CAACS,QAAT,CAAkBF,GAAlB,CAAP;AACD,GAJsB,CAAzB;AAKA,SAAOJ,gBAAgB,CAACO,MAAjB,GACHC,IAAI,CAACC,GAAL,CAAS,GAAGT,gBAAZ,CADG,GAEHD,eAFJ;AAGD","sourcesContent":["export function getMinPriority(\n Priority: { fromName: (key: any) => number },\n priorities: { [key: string]: boolean },\n defaultPriority: number\n): number {\n const parsedPriorities = Object.keys(priorities)\n .filter((key: string) => priorities[key])\n .map((key: string) => {\n return Priority.fromName(key);\n });\n return parsedPriorities.length\n ? Math.min(...parsedPriorities)\n : defaultPriority;\n}\n"],"file":"utils.js"}

View File

@@ -0,0 +1,76 @@
# Node API
## Example
```ts
import {
logkitty,
makeTagsFilter,
formatEntry,
formatError,
Priority,
Entry,
} from 'logkitty';
const emitter = logkitty({
platform: 'android',
minPriority: Priority.VERBOSE,
filter: makeTagsFilter('ReactNative', 'ReactNativeJS'),
});
emitter.on('entry', (entry: Entry) => {
console.log(formatEntry(entry));
});
emitter.on('error', (error: Error) => {
console.log(formatError(error));
});
```
## API
#### `logkitty(options: LogkittyOptions): EventEmitter`
Spawns logkitty with given options:
* `platform: 'android' | 'ios'` - Platform to get the logs from: uses `adb logcat` for Android and `xcrun simctl` + `log` for iOS simulator`.
* `adbPath?: string` - Custom path to adb tool or `undefined` (used only when `platform` is `android`).
* `priority?: number` - Minimum priority of entries to show of `undefined`, which will include all entries with priority **DEBUG** (Android)/**DEFAULT** (iOS) or above.
* `filter?: FilterCreator` - The returned value from `makeTagsFilter`/`makeAppFilter`/`makeMatchFilter`/`makeCustomFilter` or `undefined`, which will include all entries (similar to `all` command in the CLI).
When spawning logkitty you will get a instance of `EventEmitter` which emits the following events:
* `entry` (arguments: `entry: Entry`) - Emitted when new log comes in, that matches the `filter` and `priority` options. It is your responsibility to print or use that entry, for example you can use `formatEntry` to print it with the same styling as in the CLI.
* `error` (arguments: `error: Error`) - Emitted when the log can't be parsed into a entry or when the Logcat process emits an error. You can use `formatError` to print it with the same styling as in the CLI.
#### `makeTagsFilter(...tags: string[]): FilterCreator`
Available for both Android and iOS.
Creates a filter from given tags (for example `ReactNative`, `ReactNativeJS`), so only entries matching any of the given tags will be emitted in `entry` event. Pass the returned value to `filter` property when running `logkitty`.
#### `makeAppFilter(appIdentifier: string): FilterCreator`
__Available only for Android.__
Creates a filter for given application identifier (for example `com.example.app`), so only entries from given app will be emitted in `entry` event. Pass the returned value to `filter` property when running `logkitty`.
#### `makeMatchFilter(...regexes: RegExp[]): FilterCreator`
Available for both Android and iOS.
Creates a filter from given regexes (for example `/ReactNative/gm`, `/ReactNativeJS/gm`), so only entries matching any of the given regexes will be emitted in `entry` event. Pass the returned value to `filter` property when running `logkitty`.
#### `makeCustomFilter(...patterns: string[]): FilterCreator`
__Available only for Android.__
Creates a custom filter (for example `*:S`, `ReactNative:D`, `Hello:E`), so only entries matching given patterns will be emitted in `entry` event. Pass the returned value to `filter` property when running `logkitty`.
#### `formatEntry(entry: Entry): string`
Takes an entry as formats it to a string with ANSI escape codes for coloring.
#### `formatError(error: Error): string`
Takes an error and formats it to a string with ANSI escape codes for coloring.

View File

@@ -0,0 +1,76 @@
# Change Log
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.
## [6.0.0](https://www.github.com/yargs/cliui/compare/v5.0.0...v6.0.0) (2019-11-10)
### ⚠ BREAKING CHANGES
* update deps, drop Node 6
### Code Refactoring
* update deps, drop Node 6 ([62056df](https://www.github.com/yargs/cliui/commit/62056df))
## [5.0.0](https://github.com/yargs/cliui/compare/v4.1.0...v5.0.0) (2019-04-10)
### Bug Fixes
* Update wrap-ansi to fix compatibility with latest versions of chalk. ([#60](https://github.com/yargs/cliui/issues/60)) ([7bf79ae](https://github.com/yargs/cliui/commit/7bf79ae))
### BREAKING CHANGES
* Drop support for node < 6.
<a name="4.1.0"></a>
## [4.1.0](https://github.com/yargs/cliui/compare/v4.0.0...v4.1.0) (2018-04-23)
### Features
* add resetOutput method ([#57](https://github.com/yargs/cliui/issues/57)) ([7246902](https://github.com/yargs/cliui/commit/7246902))
<a name="4.0.0"></a>
## [4.0.0](https://github.com/yargs/cliui/compare/v3.2.0...v4.0.0) (2017-12-18)
### Bug Fixes
* downgrades strip-ansi to version 3.0.1 ([#54](https://github.com/yargs/cliui/issues/54)) ([5764c46](https://github.com/yargs/cliui/commit/5764c46))
* set env variable FORCE_COLOR. ([#56](https://github.com/yargs/cliui/issues/56)) ([7350e36](https://github.com/yargs/cliui/commit/7350e36))
### Chores
* drop support for node < 4 ([#53](https://github.com/yargs/cliui/issues/53)) ([b105376](https://github.com/yargs/cliui/commit/b105376))
### Features
* add fallback for window width ([#45](https://github.com/yargs/cliui/issues/45)) ([d064922](https://github.com/yargs/cliui/commit/d064922))
### BREAKING CHANGES
* officially drop support for Node < 4
<a name="3.2.0"></a>
## [3.2.0](https://github.com/yargs/cliui/compare/v3.1.2...v3.2.0) (2016-04-11)
### Bug Fixes
* reduces tarball size ([acc6c33](https://github.com/yargs/cliui/commit/acc6c33))
### Features
* adds standard-version for release management ([ff84e32](https://github.com/yargs/cliui/commit/ff84e32))

View File

@@ -0,0 +1,14 @@
Copyright (c) 2015, Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,115 @@
# cliui
[![Build Status](https://travis-ci.org/yargs/cliui.svg)](https://travis-ci.org/yargs/cliui)
[![Coverage Status](https://coveralls.io/repos/yargs/cliui/badge.svg?branch=)](https://coveralls.io/r/yargs/cliui?branch=)
[![NPM version](https://img.shields.io/npm/v/cliui.svg)](https://www.npmjs.com/package/cliui)
[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)
easily create complex multi-column command-line-interfaces.
## Example
```js
var ui = require('cliui')()
ui.div('Usage: $0 [command] [options]')
ui.div({
text: 'Options:',
padding: [2, 0, 2, 0]
})
ui.div(
{
text: "-f, --file",
width: 20,
padding: [0, 4, 0, 4]
},
{
text: "the file to load." +
chalk.green("(if this description is long it wraps).")
,
width: 20
},
{
text: chalk.red("[required]"),
align: 'right'
}
)
console.log(ui.toString())
```
<img width="500" src="screenshot.png">
## Layout DSL
cliui exposes a simple layout DSL:
If you create a single `ui.div`, passing a string rather than an
object:
* `\n`: characters will be interpreted as new rows.
* `\t`: characters will be interpreted as new columns.
* `\s`: characters will be interpreted as padding.
**as an example...**
```js
var ui = require('./')({
width: 60
})
ui.div(
'Usage: node ./bin/foo.js\n' +
' <regex>\t provide a regex\n' +
' <glob>\t provide a glob\t [required]'
)
console.log(ui.toString())
```
**will output:**
```shell
Usage: node ./bin/foo.js
<regex> provide a regex
<glob> provide a glob [required]
```
## Methods
```js
cliui = require('cliui')
```
### cliui({width: integer})
Specify the maximum width of the UI being generated.
If no width is provided, cliui will try to get the current window's width and use it, and if that doesn't work, width will be set to `80`.
### cliui({wrap: boolean})
Enable or disable the wrapping of text in a column.
### cliui.div(column, column, column)
Create a row with any number of columns, a column
can either be a string, or an object with the following
options:
* **text:** some text to place in the column.
* **width:** the width of a column.
* **align:** alignment, `right` or `center`.
* **padding:** `[top, right, bottom, left]`.
* **border:** should a border be placed around the div?
### cliui.span(column, column, column)
Similar to `div`, except the next row will be appended without
a new line being created.
### cliui.resetOutput()
Resets the UI elements of the current cliui instance, maintaining the values
set for `width` and `wrap`.

View File

@@ -0,0 +1,354 @@
'use strict'
const stringWidth = require('string-width')
const stripAnsi = require('strip-ansi')
const wrap = require('wrap-ansi')
const align = {
right: alignRight,
center: alignCenter
}
const top = 0
const right = 1
const bottom = 2
const left = 3
class UI {
constructor (opts) {
this.width = opts.width
this.wrap = opts.wrap
this.rows = []
}
span (...args) {
const cols = this.div(...args)
cols.span = true
}
resetOutput () {
this.rows = []
}
div (...args) {
if (args.length === 0) {
this.div('')
}
if (this.wrap && this._shouldApplyLayoutDSL(...args)) {
return this._applyLayoutDSL(args[0])
}
const cols = args.map(arg => {
if (typeof arg === 'string') {
return this._colFromString(arg)
}
return arg
})
this.rows.push(cols)
return cols
}
_shouldApplyLayoutDSL (...args) {
return args.length === 1 && typeof args[0] === 'string' &&
/[\t\n]/.test(args[0])
}
_applyLayoutDSL (str) {
const rows = str.split('\n').map(row => row.split('\t'))
let leftColumnWidth = 0
// simple heuristic for layout, make sure the
// second column lines up along the left-hand.
// don't allow the first column to take up more
// than 50% of the screen.
rows.forEach(columns => {
if (columns.length > 1 && stringWidth(columns[0]) > leftColumnWidth) {
leftColumnWidth = Math.min(
Math.floor(this.width * 0.5),
stringWidth(columns[0])
)
}
})
// generate a table:
// replacing ' ' with padding calculations.
// using the algorithmically generated width.
rows.forEach(columns => {
this.div(...columns.map((r, i) => {
return {
text: r.trim(),
padding: this._measurePadding(r),
width: (i === 0 && columns.length > 1) ? leftColumnWidth : undefined
}
}))
})
return this.rows[this.rows.length - 1]
}
_colFromString (text) {
return {
text,
padding: this._measurePadding(text)
}
}
_measurePadding (str) {
// measure padding without ansi escape codes
const noAnsi = stripAnsi(str)
return [0, noAnsi.match(/\s*$/)[0].length, 0, noAnsi.match(/^\s*/)[0].length]
}
toString () {
const lines = []
this.rows.forEach(row => {
this.rowToString(row, lines)
})
// don't display any lines with the
// hidden flag set.
return lines
.filter(line => !line.hidden)
.map(line => line.text)
.join('\n')
}
rowToString (row, lines) {
this._rasterize(row).forEach((rrow, r) => {
let str = ''
rrow.forEach((col, c) => {
const { width } = row[c] // the width with padding.
const wrapWidth = this._negatePadding(row[c]) // the width without padding.
let ts = col // temporary string used during alignment/padding.
if (wrapWidth > stringWidth(col)) {
ts += ' '.repeat(wrapWidth - stringWidth(col))
}
// align the string within its column.
if (row[c].align && row[c].align !== 'left' && this.wrap) {
ts = align[row[c].align](ts, wrapWidth)
if (stringWidth(ts) < wrapWidth) {
ts += ' '.repeat(width - stringWidth(ts) - 1)
}
}
// apply border and padding to string.
const padding = row[c].padding || [0, 0, 0, 0]
if (padding[left]) {
str += ' '.repeat(padding[left])
}
str += addBorder(row[c], ts, '| ')
str += ts
str += addBorder(row[c], ts, ' |')
if (padding[right]) {
str += ' '.repeat(padding[right])
}
// if prior row is span, try to render the
// current row on the prior line.
if (r === 0 && lines.length > 0) {
str = this._renderInline(str, lines[lines.length - 1])
}
})
// remove trailing whitespace.
lines.push({
text: str.replace(/ +$/, ''),
span: row.span
})
})
return lines
}
// if the full 'source' can render in
// the target line, do so.
_renderInline (source, previousLine) {
const leadingWhitespace = source.match(/^ */)[0].length
const target = previousLine.text
const targetTextWidth = stringWidth(target.trimRight())
if (!previousLine.span) {
return source
}
// if we're not applying wrapping logic,
// just always append to the span.
if (!this.wrap) {
previousLine.hidden = true
return target + source
}
if (leadingWhitespace < targetTextWidth) {
return source
}
previousLine.hidden = true
return target.trimRight() + ' '.repeat(leadingWhitespace - targetTextWidth) + source.trimLeft()
}
_rasterize (row) {
const rrows = []
const widths = this._columnWidths(row)
let wrapped
// word wrap all columns, and create
// a data-structure that is easy to rasterize.
row.forEach((col, c) => {
// leave room for left and right padding.
col.width = widths[c]
if (this.wrap) {
wrapped = wrap(col.text, this._negatePadding(col), { hard: true }).split('\n')
} else {
wrapped = col.text.split('\n')
}
if (col.border) {
wrapped.unshift('.' + '-'.repeat(this._negatePadding(col) + 2) + '.')
wrapped.push("'" + '-'.repeat(this._negatePadding(col) + 2) + "'")
}
// add top and bottom padding.
if (col.padding) {
wrapped.unshift(...new Array(col.padding[top] || 0).fill(''))
wrapped.push(...new Array(col.padding[bottom] || 0).fill(''))
}
wrapped.forEach((str, r) => {
if (!rrows[r]) {
rrows.push([])
}
const rrow = rrows[r]
for (let i = 0; i < c; i++) {
if (rrow[i] === undefined) {
rrow.push('')
}
}
rrow.push(str)
})
})
return rrows
}
_negatePadding (col) {
let wrapWidth = col.width
if (col.padding) {
wrapWidth -= (col.padding[left] || 0) + (col.padding[right] || 0)
}
if (col.border) {
wrapWidth -= 4
}
return wrapWidth
}
_columnWidths (row) {
if (!this.wrap) {
return row.map(col => {
return col.width || stringWidth(col.text)
})
}
let unset = row.length
let remainingWidth = this.width
// column widths can be set in config.
const widths = row.map(col => {
if (col.width) {
unset--
remainingWidth -= col.width
return col.width
}
return undefined
})
// any unset widths should be calculated.
const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0
return widths.map((w, i) => {
if (w === undefined) {
return Math.max(unsetWidth, _minWidth(row[i]))
}
return w
})
}
}
function addBorder (col, ts, style) {
if (col.border) {
if (/[.']-+[.']/.test(ts)) {
return ''
}
if (ts.trim().length !== 0) {
return style
}
return ' '
}
return ''
}
// calculates the minimum width of
// a column, based on padding preferences.
function _minWidth (col) {
const padding = col.padding || []
const minWidth = 1 + (padding[left] || 0) + (padding[right] || 0)
if (col.border) {
return minWidth + 4
}
return minWidth
}
function getWindowWidth () {
/* istanbul ignore next: depends on terminal */
if (typeof process === 'object' && process.stdout && process.stdout.columns) {
return process.stdout.columns
}
}
function alignRight (str, width) {
str = str.trim()
const strWidth = stringWidth(str)
if (strWidth < width) {
return ' '.repeat(width - strWidth) + str
}
return str
}
function alignCenter (str, width) {
str = str.trim()
const strWidth = stringWidth(str)
/* istanbul ignore next */
if (strWidth >= width) {
return str
}
return ' '.repeat((width - strWidth) >> 1) + str
}
module.exports = function (opts = {}) {
return new UI({
width: opts.width || getWindowWidth() || /* istanbul ignore next */ 80,
wrap: opts.wrap !== false
})
}

View File

@@ -0,0 +1,65 @@
{
"name": "cliui",
"version": "6.0.0",
"description": "easily create complex multi-column command-line-interfaces",
"main": "index.js",
"scripts": {
"pretest": "standard",
"test": "nyc mocha",
"coverage": "nyc --reporter=text-lcov mocha | coveralls"
},
"repository": {
"type": "git",
"url": "http://github.com/yargs/cliui.git"
},
"config": {
"blanket": {
"pattern": [
"index.js"
],
"data-cover-never": [
"node_modules",
"test"
],
"output-reporter": "spec"
}
},
"standard": {
"ignore": [
"**/example/**"
],
"globals": [
"it"
]
},
"keywords": [
"cli",
"command-line",
"layout",
"design",
"console",
"wrap",
"table"
],
"author": "Ben Coe <ben@npmjs.com>",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
},
"devDependencies": {
"chai": "^4.2.0",
"chalk": "^3.0.0",
"coveralls": "^3.0.3",
"mocha": "^6.2.2",
"nyc": "^14.1.1",
"standard": "^12.0.1"
},
"files": [
"index.js"
],
"engine": {
"node": ">=8"
}
}

View File

@@ -0,0 +1,137 @@
import {Options as LocatePathOptions} from 'locate-path';
declare const stop: unique symbol;
declare namespace findUp {
interface Options extends LocatePathOptions {}
type StopSymbol = typeof stop;
type Match = string | StopSymbol | undefined;
}
declare const findUp: {
/**
Find a file or directory by walking up parent directories.
@param name - Name of the file or directory to find. Can be multiple.
@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.
@example
```
// /
// └── Users
// └── sindresorhus
// ├── unicorn.png
// └── foo
// └── bar
// ├── baz
// └── example.js
// example.js
import findUp = require('find-up');
(async () => {
console.log(await findUp('unicorn.png'));
//=> '/Users/sindresorhus/unicorn.png'
console.log(await findUp(['rainbow.png', 'unicorn.png']));
//=> '/Users/sindresorhus/unicorn.png'
})();
```
*/
(name: string | string[], options?: findUp.Options): Promise<string | undefined>;
/**
Find a file or directory by walking up parent directories.
@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
@returns The first path found or `undefined` if none could be found.
@example
```
import path = require('path');
import findUp = require('find-up');
(async () => {
console.log(await findUp(async directory => {
const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
})();
```
*/
(matcher: (directory: string) => (findUp.Match | Promise<findUp.Match>), options?: findUp.Options): Promise<string | undefined>;
sync: {
/**
Synchronously find a file or directory by walking up parent directories.
@param name - Name of the file or directory to find. Can be multiple.
@returns The first path found (by respecting the order of `name`s) or `undefined` if none could be found.
*/
(name: string | string[], options?: findUp.Options): string | undefined;
/**
Synchronously find a file or directory by walking up parent directories.
@param matcher - Called for each directory in the search. Return a path or `findUp.stop` to stop the search.
@returns The first path found or `undefined` if none could be found.
@example
```
import path = require('path');
import findUp = require('find-up');
console.log(findUp.sync(directory => {
const hasUnicorns = findUp.sync.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
```
*/
(matcher: (directory: string) => findUp.Match, options?: findUp.Options): string | undefined;
/**
Synchronously check if a path exists.
@param path - Path to the file or directory.
@returns Whether the path exists.
@example
```
import findUp = require('find-up');
console.log(findUp.sync.exists('/Users/sindresorhus/unicorn.png'));
//=> true
```
*/
exists(path: string): boolean;
}
/**
Check if a path exists.
@param path - Path to a file or directory.
@returns Whether the path exists.
@example
```
import findUp = require('find-up');
(async () => {
console.log(await findUp.exists('/Users/sindresorhus/unicorn.png'));
//=> true
})();
```
*/
exists(path: string): Promise<boolean>;
/**
Return this in a `matcher` function to stop the search and force `findUp` to immediately return `undefined`.
*/
readonly stop: findUp.StopSymbol;
};
export = findUp;

View File

@@ -0,0 +1,89 @@
'use strict';
const path = require('path');
const locatePath = require('locate-path');
const pathExists = require('path-exists');
const stop = Symbol('findUp.stop');
module.exports = async (name, options = {}) => {
let directory = path.resolve(options.cwd || '');
const {root} = path.parse(directory);
const paths = [].concat(name);
const runMatcher = async locateOptions => {
if (typeof name !== 'function') {
return locatePath(paths, locateOptions);
}
const foundPath = await name(locateOptions.cwd);
if (typeof foundPath === 'string') {
return locatePath([foundPath], locateOptions);
}
return foundPath;
};
// eslint-disable-next-line no-constant-condition
while (true) {
// eslint-disable-next-line no-await-in-loop
const foundPath = await runMatcher({...options, cwd: directory});
if (foundPath === stop) {
return;
}
if (foundPath) {
return path.resolve(directory, foundPath);
}
if (directory === root) {
return;
}
directory = path.dirname(directory);
}
};
module.exports.sync = (name, options = {}) => {
let directory = path.resolve(options.cwd || '');
const {root} = path.parse(directory);
const paths = [].concat(name);
const runMatcher = locateOptions => {
if (typeof name !== 'function') {
return locatePath.sync(paths, locateOptions);
}
const foundPath = name(locateOptions.cwd);
if (typeof foundPath === 'string') {
return locatePath.sync([foundPath], locateOptions);
}
return foundPath;
};
// eslint-disable-next-line no-constant-condition
while (true) {
const foundPath = runMatcher({...options, cwd: directory});
if (foundPath === stop) {
return;
}
if (foundPath) {
return path.resolve(directory, foundPath);
}
if (directory === root) {
return;
}
directory = path.dirname(directory);
}
};
module.exports.exists = pathExists;
module.exports.sync.exists = pathExists.sync;
module.exports.stop = stop;

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,53 @@
{
"name": "find-up",
"version": "4.1.0",
"description": "Find a file or directory by walking up parent directories",
"license": "MIT",
"repository": "sindresorhus/find-up",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"engines": {
"node": ">=8"
},
"scripts": {
"test": "xo && ava && tsd"
},
"files": [
"index.js",
"index.d.ts"
],
"keywords": [
"find",
"up",
"find-up",
"findup",
"look-up",
"look",
"file",
"search",
"match",
"package",
"resolve",
"parent",
"parents",
"folder",
"directory",
"walk",
"walking",
"path"
],
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"devDependencies": {
"ava": "^2.1.0",
"is-path-inside": "^2.1.0",
"tempy": "^0.3.0",
"tsd": "^0.7.3",
"xo": "^0.24.0"
}
}

View File

@@ -0,0 +1,156 @@
# find-up [![Build Status](https://travis-ci.org/sindresorhus/find-up.svg?branch=master)](https://travis-ci.org/sindresorhus/find-up)
> Find a file or directory by walking up parent directories
## Install
```
$ npm install find-up
```
## Usage
```
/
└── Users
└── sindresorhus
├── unicorn.png
└── foo
└── bar
├── baz
└── example.js
```
`example.js`
```js
const path = require('path');
const findUp = require('find-up');
(async () => {
console.log(await findUp('unicorn.png'));
//=> '/Users/sindresorhus/unicorn.png'
console.log(await findUp(['rainbow.png', 'unicorn.png']));
//=> '/Users/sindresorhus/unicorn.png'
console.log(await findUp(async directory => {
const hasUnicorns = await findUp.exists(path.join(directory, 'unicorn.png'));
return hasUnicorns && directory;
}, {type: 'directory'}));
//=> '/Users/sindresorhus'
})();
```
## API
### findUp(name, options?)
### findUp(matcher, options?)
Returns a `Promise` for either the path or `undefined` if it couldn't be found.
### findUp([...name], options?)
Returns a `Promise` for either the first path found (by respecting the order of the array) or `undefined` if none could be found.
### findUp.sync(name, options?)
### findUp.sync(matcher, options?)
Returns a path or `undefined` if it couldn't be found.
### findUp.sync([...name], options?)
Returns the first path found (by respecting the order of the array) or `undefined` if none could be found.
#### name
Type: `string`
Name of the file or directory to find.
#### matcher
Type: `Function`
A function that will be called with each directory until it returns a `string` with the path, which stops the search, or the root directory has been reached and nothing was found. Useful if you want to match files with certain patterns, set of permissions, or other advanced use-cases.
When using async mode, the `matcher` may optionally be an async or promise-returning function that returns the path.
#### options
Type: `object`
##### cwd
Type: `string`<br>
Default: `process.cwd()`
Directory to start from.
##### type
Type: `string`<br>
Default: `'file'`<br>
Values: `'file'` `'directory'`
The type of paths that can match.
##### allowSymlinks
Type: `boolean`<br>
Default: `true`
Allow symbolic links to match if they point to the chosen path type.
### findUp.exists(path)
Returns a `Promise<boolean>` of whether the path exists.
### findUp.sync.exists(path)
Returns a `boolean` of whether the path exists.
#### path
Type: `string`
Path to a file or directory.
### findUp.stop
A [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) that can be returned by a `matcher` function to stop the search and cause `findUp` to immediately return `undefined`. Useful as a performance optimization in case the current working directory is deeply nested in the filesystem.
```js
const path = require('path');
const findUp = require('find-up');
(async () => {
await findUp(directory => {
return path.basename(directory) === 'work' ? findUp.stop : 'logo.png';
});
})();
```
## Related
- [find-up-cli](https://github.com/sindresorhus/find-up-cli) - CLI for this module
- [pkg-up](https://github.com/sindresorhus/pkg-up) - Find the closest package.json file
- [pkg-dir](https://github.com/sindresorhus/pkg-dir) - Find the root directory of an npm package
- [resolve-from](https://github.com/sindresorhus/resolve-from) - Resolve the path of a module like `require.resolve()` but from a given path
---
<div align="center">
<b>
<a href="https://tidelift.com/subscription/pkg/npm-find-up?utm_source=npm-find-up&utm_medium=referral&utm_campaign=readme">Get professional support for 'find-up' with a Tidelift subscription</a>
</b>
<br>
<sub>
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
</sub>
</div>

View File

@@ -0,0 +1,83 @@
declare namespace locatePath {
interface Options {
/**
Current working directory.
@default process.cwd()
*/
readonly cwd?: string;
/**
Type of path to match.
@default 'file'
*/
readonly type?: 'file' | 'directory';
/**
Allow symbolic links to match if they point to the requested path type.
@default true
*/
readonly allowSymlinks?: boolean;
}
interface AsyncOptions extends Options {
/**
Number of concurrently pending promises. Minimum: `1`.
@default Infinity
*/
readonly concurrency?: number;
/**
Preserve `paths` order when searching.
Disable this to improve performance if you don't care about the order.
@default true
*/
readonly preserveOrder?: boolean;
}
}
declare const locatePath: {
/**
Get the first path that exists on disk of multiple paths.
@param paths - Paths to check.
@returns The first path that exists or `undefined` if none exists.
@example
```
import locatePath = require('locate-path');
const files = [
'unicorn.png',
'rainbow.png', // Only this one actually exists on disk
'pony.png'
];
(async () => {
console(await locatePath(files));
//=> 'rainbow'
})();
```
*/
(paths: Iterable<string>, options?: locatePath.AsyncOptions): Promise<
string | undefined
>;
/**
Synchronously get the first path that exists on disk of multiple paths.
@param paths - Paths to check.
@returns The first path that exists or `undefined` if none exists.
*/
sync(
paths: Iterable<string>,
options?: locatePath.Options
): string | undefined;
};
export = locatePath;

View File

@@ -0,0 +1,65 @@
'use strict';
const path = require('path');
const fs = require('fs');
const {promisify} = require('util');
const pLocate = require('p-locate');
const fsStat = promisify(fs.stat);
const fsLStat = promisify(fs.lstat);
const typeMappings = {
directory: 'isDirectory',
file: 'isFile'
};
function checkType({type}) {
if (type in typeMappings) {
return;
}
throw new Error(`Invalid type specified: ${type}`);
}
const matchType = (type, stat) => type === undefined || stat[typeMappings[type]]();
module.exports = async (paths, options) => {
options = {
cwd: process.cwd(),
type: 'file',
allowSymlinks: true,
...options
};
checkType(options);
const statFn = options.allowSymlinks ? fsStat : fsLStat;
return pLocate(paths, async path_ => {
try {
const stat = await statFn(path.resolve(options.cwd, path_));
return matchType(options.type, stat);
} catch (_) {
return false;
}
}, options);
};
module.exports.sync = (paths, options) => {
options = {
cwd: process.cwd(),
allowSymlinks: true,
type: 'file',
...options
};
checkType(options);
const statFn = options.allowSymlinks ? fs.statSync : fs.lstatSync;
for (const path_ of paths) {
try {
const stat = statFn(path.resolve(options.cwd, path_));
if (matchType(options.type, stat)) {
return path_;
}
} catch (_) {
}
}
};

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,45 @@
{
"name": "locate-path",
"version": "5.0.0",
"description": "Get the first path that exists on disk of multiple paths",
"license": "MIT",
"repository": "sindresorhus/locate-path",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"engines": {
"node": ">=8"
},
"scripts": {
"test": "xo && ava && tsd"
},
"files": [
"index.js",
"index.d.ts"
],
"keywords": [
"locate",
"path",
"paths",
"file",
"files",
"exists",
"find",
"finder",
"search",
"searcher",
"array",
"iterable",
"iterator"
],
"dependencies": {
"p-locate": "^4.1.0"
},
"devDependencies": {
"ava": "^1.4.1",
"tsd": "^0.7.2",
"xo": "^0.24.0"
}
}

View File

@@ -0,0 +1,122 @@
# locate-path [![Build Status](https://travis-ci.org/sindresorhus/locate-path.svg?branch=master)](https://travis-ci.org/sindresorhus/locate-path)
> Get the first path that exists on disk of multiple paths
## Install
```
$ npm install locate-path
```
## Usage
Here we find the first file that exists on disk, in array order.
```js
const locatePath = require('locate-path');
const files = [
'unicorn.png',
'rainbow.png', // Only this one actually exists on disk
'pony.png'
];
(async () => {
console(await locatePath(files));
//=> 'rainbow'
})();
```
## API
### locatePath(paths, [options])
Returns a `Promise<string>` for the first path that exists or `undefined` if none exists.
#### paths
Type: `Iterable<string>`
Paths to check.
#### options
Type: `Object`
##### concurrency
Type: `number`<br>
Default: `Infinity`<br>
Minimum: `1`
Number of concurrently pending promises.
##### preserveOrder
Type: `boolean`<br>
Default: `true`
Preserve `paths` order when searching.
Disable this to improve performance if you don't care about the order.
##### cwd
Type: `string`<br>
Default: `process.cwd()`
Current working directory.
##### type
Type: `string`<br>
Default: `file`<br>
Values: `file` `directory`
The type of paths that can match.
##### allowSymlinks
Type: `boolean`<br>
Default: `true`
Allow symbolic links to match if they point to the chosen path type.
### locatePath.sync(paths, [options])
Returns the first path that exists or `undefined` if none exists.
#### paths
Type: `Iterable<string>`
Paths to check.
#### options
Type: `Object`
##### cwd
Same as above.
##### type
Same as above.
##### allowSymlinks
Same as above.
## Related
- [path-exists](https://github.com/sindresorhus/path-exists) - Check if a path exists
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)

View File

@@ -0,0 +1,38 @@
export interface Limit {
/**
@param fn - Promise-returning/async function.
@param arguments - Any arguments to pass through to `fn`. Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a lot of functions.
@returns The promise returned by calling `fn(...arguments)`.
*/
<Arguments extends unknown[], ReturnType>(
fn: (...arguments: Arguments) => PromiseLike<ReturnType> | ReturnType,
...arguments: Arguments
): Promise<ReturnType>;
/**
The number of promises that are currently running.
*/
readonly activeCount: number;
/**
The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
*/
readonly pendingCount: number;
/**
Discard pending promises that are waiting to run.
This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
Note: This does not cancel promises that are already running.
*/
clearQueue(): void;
}
/**
Run multiple promise-returning & async functions with limited concurrency.
@param concurrency - Concurrency limit. Minimum: `1`.
@returns A `limit` function.
*/
export default function pLimit(concurrency: number): Limit;

View File

@@ -0,0 +1,57 @@
'use strict';
const pTry = require('p-try');
const pLimit = concurrency => {
if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
return Promise.reject(new TypeError('Expected `concurrency` to be a number from 1 and up'));
}
const queue = [];
let activeCount = 0;
const next = () => {
activeCount--;
if (queue.length > 0) {
queue.shift()();
}
};
const run = (fn, resolve, ...args) => {
activeCount++;
const result = pTry(fn, ...args);
resolve(result);
result.then(next, next);
};
const enqueue = (fn, resolve, ...args) => {
if (activeCount < concurrency) {
run(fn, resolve, ...args);
} else {
queue.push(run.bind(null, fn, resolve, ...args));
}
};
const generator = (fn, ...args) => new Promise(resolve => enqueue(fn, resolve, ...args));
Object.defineProperties(generator, {
activeCount: {
get: () => activeCount
},
pendingCount: {
get: () => queue.length
},
clearQueue: {
value: () => {
queue.length = 0;
}
}
});
return generator;
};
module.exports = pLimit;
module.exports.default = pLimit;

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,52 @@
{
"name": "p-limit",
"version": "2.3.0",
"description": "Run multiple promise-returning & async functions with limited concurrency",
"license": "MIT",
"repository": "sindresorhus/p-limit",
"funding": "https://github.com/sponsors/sindresorhus",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"engines": {
"node": ">=6"
},
"scripts": {
"test": "xo && ava && tsd-check"
},
"files": [
"index.js",
"index.d.ts"
],
"keywords": [
"promise",
"limit",
"limited",
"concurrency",
"throttle",
"throat",
"rate",
"batch",
"ratelimit",
"task",
"queue",
"async",
"await",
"promises",
"bluebird"
],
"dependencies": {
"p-try": "^2.0.0"
},
"devDependencies": {
"ava": "^1.2.1",
"delay": "^4.1.0",
"in-range": "^1.0.0",
"random-int": "^1.0.0",
"time-span": "^2.0.0",
"tsd-check": "^0.3.0",
"xo": "^0.24.0"
}
}

View File

@@ -0,0 +1,101 @@
# p-limit [![Build Status](https://travis-ci.org/sindresorhus/p-limit.svg?branch=master)](https://travis-ci.org/sindresorhus/p-limit)
> Run multiple promise-returning & async functions with limited concurrency
## Install
```
$ npm install p-limit
```
## Usage
```js
const pLimit = require('p-limit');
const limit = pLimit(1);
const input = [
limit(() => fetchSomething('foo')),
limit(() => fetchSomething('bar')),
limit(() => doSomething())
];
(async () => {
// Only one promise is run at once
const result = await Promise.all(input);
console.log(result);
})();
```
## API
### pLimit(concurrency)
Returns a `limit` function.
#### concurrency
Type: `number`\
Minimum: `1`\
Default: `Infinity`
Concurrency limit.
### limit(fn, ...args)
Returns the promise returned by calling `fn(...args)`.
#### fn
Type: `Function`
Promise-returning/async function.
#### args
Any arguments to pass through to `fn`.
Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a *lot* of functions.
### limit.activeCount
The number of promises that are currently running.
### limit.pendingCount
The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
### limit.clearQueue()
Discard pending promises that are waiting to run.
This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
Note: This does not cancel promises that are already running.
## FAQ
### How is this different from the [`p-queue`](https://github.com/sindresorhus/p-queue) package?
This package is only about limiting the number of concurrent executions, while `p-queue` is a fully featured queue implementation with lots of different options, introspection, and ability to pause the queue.
## Related
- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control
- [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
- [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
- [More…](https://github.com/sindresorhus/promise-fun)
---
<div align="center">
<b>
<a href="https://tidelift.com/subscription/pkg/npm-p-limit?utm_source=npm-p-limit&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
</b>
<br>
<sub>
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
</sub>
</div>

View File

@@ -0,0 +1,64 @@
declare namespace pLocate {
interface Options {
/**
Number of concurrently pending promises returned by `tester`. Minimum: `1`.
@default Infinity
*/
readonly concurrency?: number;
/**
Preserve `input` order when searching.
Disable this to improve performance if you don't care about the order.
@default true
*/
readonly preserveOrder?: boolean;
}
}
declare const pLocate: {
/**
Get the first fulfilled promise that satisfies the provided testing function.
@param input - An iterable of promises/values to test.
@param tester - This function will receive resolved values from `input` and is expected to return a `Promise<boolean>` or `boolean`.
@returns A `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.
@example
```
import pathExists = require('path-exists');
import pLocate = require('p-locate');
const files = [
'unicorn.png',
'rainbow.png', // Only this one actually exists on disk
'pony.png'
];
(async () => {
const foundPath = await pLocate(files, file => pathExists(file));
console.log(foundPath);
//=> 'rainbow'
})();
```
*/
<ValueType>(
input: Iterable<PromiseLike<ValueType> | ValueType>,
tester: (element: ValueType) => PromiseLike<boolean> | boolean,
options?: pLocate.Options
): Promise<ValueType | undefined>;
// TODO: Remove this for the next major release, refactor the whole definition to:
// declare function pLocate<ValueType>(
// input: Iterable<PromiseLike<ValueType> | ValueType>,
// tester: (element: ValueType) => PromiseLike<boolean> | boolean,
// options?: pLocate.Options
// ): Promise<ValueType | undefined>;
// export = pLocate;
default: typeof pLocate;
};
export = pLocate;

View File

@@ -0,0 +1,52 @@
'use strict';
const pLimit = require('p-limit');
class EndError extends Error {
constructor(value) {
super();
this.value = value;
}
}
// The input can also be a promise, so we await it
const testElement = async (element, tester) => tester(await element);
// The input can also be a promise, so we `Promise.all()` them both
const finder = async element => {
const values = await Promise.all(element);
if (values[1] === true) {
throw new EndError(values[0]);
}
return false;
};
const pLocate = async (iterable, tester, options) => {
options = {
concurrency: Infinity,
preserveOrder: true,
...options
};
const limit = pLimit(options.concurrency);
// Start all the promises concurrently with optional limit
const items = [...iterable].map(element => [element, limit(testElement, element, tester)]);
// Check the promises either serially or concurrently
const checkLimit = pLimit(options.preserveOrder ? 1 : Infinity);
try {
await Promise.all(items.map(element => checkLimit(finder, element)));
} catch (error) {
if (error instanceof EndError) {
return error.value;
}
throw error;
}
};
module.exports = pLocate;
// TODO: Remove this for the next major release
module.exports.default = pLocate;

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,53 @@
{
"name": "p-locate",
"version": "4.1.0",
"description": "Get the first fulfilled promise that satisfies the provided testing function",
"license": "MIT",
"repository": "sindresorhus/p-locate",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"engines": {
"node": ">=8"
},
"scripts": {
"test": "xo && ava && tsd"
},
"files": [
"index.js",
"index.d.ts"
],
"keywords": [
"promise",
"locate",
"find",
"finder",
"search",
"searcher",
"test",
"array",
"collection",
"iterable",
"iterator",
"race",
"fulfilled",
"fastest",
"async",
"await",
"promises",
"bluebird"
],
"dependencies": {
"p-limit": "^2.2.0"
},
"devDependencies": {
"ava": "^1.4.1",
"delay": "^4.1.0",
"in-range": "^1.0.0",
"time-span": "^3.0.0",
"tsd": "^0.7.2",
"xo": "^0.24.0"
}
}

View File

@@ -0,0 +1,90 @@
# p-locate [![Build Status](https://travis-ci.org/sindresorhus/p-locate.svg?branch=master)](https://travis-ci.org/sindresorhus/p-locate)
> Get the first fulfilled promise that satisfies the provided testing function
Think of it like an async version of [`Array#find`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
## Install
```
$ npm install p-locate
```
## Usage
Here we find the first file that exists on disk, in array order.
```js
const pathExists = require('path-exists');
const pLocate = require('p-locate');
const files = [
'unicorn.png',
'rainbow.png', // Only this one actually exists on disk
'pony.png'
];
(async () => {
const foundPath = await pLocate(files, file => pathExists(file));
console.log(foundPath);
//=> 'rainbow'
})();
```
*The above is just an example. Use [`locate-path`](https://github.com/sindresorhus/locate-path) if you need this.*
## API
### pLocate(input, tester, [options])
Returns a `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.
#### input
Type: `Iterable<Promise | unknown>`
An iterable of promises/values to test.
#### tester(element)
Type: `Function`
This function will receive resolved values from `input` and is expected to return a `Promise<boolean>` or `boolean`.
#### options
Type: `Object`
##### concurrency
Type: `number`<br>
Default: `Infinity`<br>
Minimum: `1`
Number of concurrently pending promises returned by `tester`.
##### preserveOrder
Type: `boolean`<br>
Default: `true`
Preserve `input` order when searching.
Disable this to improve performance if you don't care about the order.
## Related
- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently
- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently
- [p-any](https://github.com/sindresorhus/p-any) - Wait for any promise to be fulfilled
- [More…](https://github.com/sindresorhus/promise-fun)
## License
MIT © [Sindre Sorhus](https://sindresorhus.com)

View File

@@ -0,0 +1,186 @@
'use strict';
const stringWidth = require('string-width');
const stripAnsi = require('strip-ansi');
const ansiStyles = require('ansi-styles');
const ESCAPES = new Set([
'\u001B',
'\u009B'
]);
const END_CODE = 39;
const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`;
// Calculate the length of words split on ' ', ignoring
// the extra characters added by ansi escape codes
const wordLengths = string => string.split(' ').map(character => stringWidth(character));
// Wrap a long word across multiple rows
// Ansi escape codes do not count towards length
const wrapWord = (rows, word, columns) => {
const characters = [...word];
let isInsideEscape = false;
let visible = stringWidth(stripAnsi(rows[rows.length - 1]));
for (const [index, character] of characters.entries()) {
const characterLength = stringWidth(character);
if (visible + characterLength <= columns) {
rows[rows.length - 1] += character;
} else {
rows.push(character);
visible = 0;
}
if (ESCAPES.has(character)) {
isInsideEscape = true;
} else if (isInsideEscape && character === 'm') {
isInsideEscape = false;
continue;
}
if (isInsideEscape) {
continue;
}
visible += characterLength;
if (visible === columns && index < characters.length - 1) {
rows.push('');
visible = 0;
}
}
// It's possible that the last row we copy over is only
// ansi escape characters, handle this edge-case
if (!visible && rows[rows.length - 1].length > 0 && rows.length > 1) {
rows[rows.length - 2] += rows.pop();
}
};
// Trims spaces from a string ignoring invisible sequences
const stringVisibleTrimSpacesRight = str => {
const words = str.split(' ');
let last = words.length;
while (last > 0) {
if (stringWidth(words[last - 1]) > 0) {
break;
}
last--;
}
if (last === words.length) {
return str;
}
return words.slice(0, last).join(' ') + words.slice(last).join('');
};
// The wrap-ansi module can be invoked in either 'hard' or 'soft' wrap mode
//
// 'hard' will never allow a string to take up more than columns characters
//
// 'soft' allows long words to expand past the column length
const exec = (string, columns, options = {}) => {
if (options.trim !== false && string.trim() === '') {
return '';
}
let pre = '';
let ret = '';
let escapeCode;
const lengths = wordLengths(string);
let rows = [''];
for (const [index, word] of string.split(' ').entries()) {
if (options.trim !== false) {
rows[rows.length - 1] = rows[rows.length - 1].trimLeft();
}
let rowLength = stringWidth(rows[rows.length - 1]);
if (index !== 0) {
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
// If we start with a new word but the current row length equals the length of the columns, add a new row
rows.push('');
rowLength = 0;
}
if (rowLength > 0 || options.trim === false) {
rows[rows.length - 1] += ' ';
rowLength++;
}
}
// In 'hard' wrap mode, the length of a line is never allowed to extend past 'columns'
if (options.hard && lengths[index] > columns) {
const remainingColumns = (columns - rowLength);
const breaksStartingThisLine = 1 + Math.floor((lengths[index] - remainingColumns - 1) / columns);
const breaksStartingNextLine = Math.floor((lengths[index] - 1) / columns);
if (breaksStartingNextLine < breaksStartingThisLine) {
rows.push('');
}
wrapWord(rows, word, columns);
continue;
}
if (rowLength + lengths[index] > columns && rowLength > 0 && lengths[index] > 0) {
if (options.wordWrap === false && rowLength < columns) {
wrapWord(rows, word, columns);
continue;
}
rows.push('');
}
if (rowLength + lengths[index] > columns && options.wordWrap === false) {
wrapWord(rows, word, columns);
continue;
}
rows[rows.length - 1] += word;
}
if (options.trim !== false) {
rows = rows.map(stringVisibleTrimSpacesRight);
}
pre = rows.join('\n');
for (const [index, character] of [...pre].entries()) {
ret += character;
if (ESCAPES.has(character)) {
const code = parseFloat(/\d[^m]*/.exec(pre.slice(index, index + 4)));
escapeCode = code === END_CODE ? null : code;
}
const code = ansiStyles.codes.get(Number(escapeCode));
if (escapeCode && code) {
if (pre[index + 1] === '\n') {
ret += wrapAnsi(code);
} else if (character === '\n') {
ret += wrapAnsi(escapeCode);
}
}
}
return ret;
};
// For each newline, invoke the method separately
module.exports = (string, columns, options) => {
return String(string)
.normalize()
.replace(/\r\n/g, '\n')
.split('\n')
.map(line => exec(line, columns, options))
.join('\n');
};

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,61 @@
{
"name": "wrap-ansi",
"version": "6.2.0",
"description": "Wordwrap a string with ANSI escape codes",
"license": "MIT",
"repository": "chalk/wrap-ansi",
"author": {
"name": "Sindre Sorhus",
"email": "sindresorhus@gmail.com",
"url": "sindresorhus.com"
},
"engines": {
"node": ">=8"
},
"scripts": {
"test": "xo && nyc ava"
},
"files": [
"index.js"
],
"keywords": [
"wrap",
"break",
"wordwrap",
"wordbreak",
"linewrap",
"ansi",
"styles",
"color",
"colour",
"colors",
"terminal",
"console",
"cli",
"string",
"tty",
"escape",
"formatting",
"rgb",
"256",
"shell",
"xterm",
"log",
"logging",
"command-line",
"text"
],
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"devDependencies": {
"ava": "^2.1.0",
"chalk": "^2.4.2",
"coveralls": "^3.0.3",
"has-ansi": "^3.0.0",
"nyc": "^14.1.1",
"xo": "^0.24.0"
}
}

View File

@@ -0,0 +1,97 @@
# wrap-ansi [![Build Status](https://travis-ci.org/chalk/wrap-ansi.svg?branch=master)](https://travis-ci.org/chalk/wrap-ansi) [![Coverage Status](https://coveralls.io/repos/github/chalk/wrap-ansi/badge.svg?branch=master)](https://coveralls.io/github/chalk/wrap-ansi?branch=master)
> Wordwrap a string with [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors_and_Styles)
## Install
```
$ npm install wrap-ansi
```
## Usage
```js
const chalk = require('chalk');
const wrapAnsi = require('wrap-ansi');
const input = 'The quick brown ' + chalk.red('fox jumped over ') +
'the lazy ' + chalk.green('dog and then ran away with the unicorn.');
console.log(wrapAnsi(input, 20));
```
<img width="331" src="screenshot.png">
## API
### wrapAnsi(string, columns, options?)
Wrap words to the specified column width.
#### string
Type: `string`
String with ANSI escape codes. Like one styled by [`chalk`](https://github.com/chalk/chalk). Newline characters will be normalized to `\n`.
#### columns
Type: `number`
Number of columns to wrap the text to.
#### options
Type: `object`
##### hard
Type: `boolean`<br>
Default: `false`
By default the wrap is soft, meaning long words may extend past the column width. Setting this to `true` will make it hard wrap at the column width.
##### wordWrap
Type: `boolean`<br>
Default: `true`
By default, an attempt is made to split words at spaces, ensuring that they don't extend past the configured columns. If wordWrap is `false`, each column will instead be completely filled splitting words as necessary.
##### trim
Type: `boolean`<br>
Default: `true`
Whitespace on all lines is removed by default. Set this option to `false` if you don't want to trim.
## Related
- [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes
- [cli-truncate](https://github.com/sindresorhus/cli-truncate) - Truncate a string to a specific width in the terminal
- [chalk](https://github.com/chalk/chalk) - Terminal string styling done right
- [jsesc](https://github.com/mathiasbynens/jsesc) - Generate ASCII-only output from Unicode strings. Useful for creating test fixtures.
## Maintainers
- [Sindre Sorhus](https://github.com/sindresorhus)
- [Josh Junon](https://github.com/qix-)
- [Benjamin Coe](https://github.com/bcoe)
---
<div align="center">
<b>
<a href="https://tidelift.com/subscription/pkg/npm-wrap_ansi?utm_source=npm-wrap-ansi&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
</b>
<br>
<sub>
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
</sub>
</div>

View File

@@ -0,0 +1,35 @@
# Change Log
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.0.3](https://www.github.com/yargs/y18n/compare/y18n-v4.0.2...y18n-v4.0.3) (2021-04-07)
### Bug Fixes
* **release:** 4.x.x should not enforce Node 10 ([#126](https://www.github.com/yargs/y18n/issues/126)) ([1e21a53](https://www.github.com/yargs/y18n/commit/1e21a536e9135d8403a47be88922157a706b7cde))
### 4.0.1 (2020-11-30)
### Bug Fixes
* address prototype pollution issue ([#108](https://www.github.com/yargs/y18n/issues/108)) ([a9ac604](https://www.github.com/yargs/y18n/commit/a9ac604abf756dec9687be3843e2c93bfe581f25))
<a name="4.0.0"></a>
# [4.0.0](https://github.com/yargs/y18n/compare/v3.2.1...v4.0.0) (2017-10-10)
### Bug Fixes
* allow support for falsy values like 0 in tagged literal ([#45](https://github.com/yargs/y18n/issues/45)) ([c926123](https://github.com/yargs/y18n/commit/c926123))
### Features
* **__:** added tagged template literal support ([#44](https://github.com/yargs/y18n/issues/44)) ([0598daf](https://github.com/yargs/y18n/commit/0598daf))
### BREAKING CHANGES
* **__:** dropping Node 0.10/Node 0.12 support

View File

@@ -0,0 +1,13 @@
Copyright (c) 2015, Contributors
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

View File

@@ -0,0 +1,109 @@
# y18n
[![Build Status][travis-image]][travis-url]
[![Coverage Status][coveralls-image]][coveralls-url]
[![NPM version][npm-image]][npm-url]
[![js-standard-style][standard-image]][standard-url]
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)
The bare-bones internationalization library used by yargs.
Inspired by [i18n](https://www.npmjs.com/package/i18n).
## Examples
_simple string translation:_
```js
var __ = require('y18n').__
console.log(__('my awesome string %s', 'foo'))
```
output:
`my awesome string foo`
_using tagged template literals_
```js
var __ = require('y18n').__
var str = 'foo'
console.log(__`my awesome string ${str}`)
```
output:
`my awesome string foo`
_pluralization support:_
```js
var __n = require('y18n').__n
console.log(__n('one fish %s', '%d fishes %s', 2, 'foo'))
```
output:
`2 fishes foo`
## JSON Language Files
The JSON language files should be stored in a `./locales` folder.
File names correspond to locales, e.g., `en.json`, `pirate.json`.
When strings are observed for the first time they will be
added to the JSON file corresponding to the current locale.
## Methods
### require('y18n')(config)
Create an instance of y18n with the config provided, options include:
* `directory`: the locale directory, default `./locales`.
* `updateFiles`: should newly observed strings be updated in file, default `true`.
* `locale`: what locale should be used.
* `fallbackToLanguage`: should fallback to a language-only file (e.g. `en.json`)
be allowed if a file matching the locale does not exist (e.g. `en_US.json`),
default `true`.
### y18n.\_\_(str, arg, arg, arg)
Print a localized string, `%s` will be replaced with `arg`s.
This function can also be used as a tag for a template literal. You can use it
like this: <code>__&#96;hello ${'world'}&#96;</code>. This will be equivalent to
`__('hello %s', 'world')`.
### y18n.\_\_n(singularString, pluralString, count, arg, arg, arg)
Print a localized string with appropriate pluralization. If `%d` is provided
in the string, the `count` will replace this placeholder.
### y18n.setLocale(str)
Set the current locale being used.
### y18n.getLocale()
What locale is currently being used?
### y18n.updateLocale(obj)
Update the current locale with the key value pairs in `obj`.
## License
ISC
[travis-url]: https://travis-ci.org/yargs/y18n
[travis-image]: https://img.shields.io/travis/yargs/y18n.svg
[coveralls-url]: https://coveralls.io/github/yargs/y18n
[coveralls-image]: https://img.shields.io/coveralls/yargs/y18n.svg
[npm-url]: https://npmjs.org/package/y18n
[npm-image]: https://img.shields.io/npm/v/y18n.svg
[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg
[standard-url]: https://github.com/feross/standard

View File

@@ -0,0 +1,188 @@
var fs = require('fs')
var path = require('path')
var util = require('util')
function Y18N (opts) {
// configurable options.
opts = opts || {}
this.directory = opts.directory || './locales'
this.updateFiles = typeof opts.updateFiles === 'boolean' ? opts.updateFiles : true
this.locale = opts.locale || 'en'
this.fallbackToLanguage = typeof opts.fallbackToLanguage === 'boolean' ? opts.fallbackToLanguage : true
// internal stuff.
this.cache = Object.create(null)
this.writeQueue = []
}
Y18N.prototype.__ = function () {
if (typeof arguments[0] !== 'string') {
return this._taggedLiteral.apply(this, arguments)
}
var args = Array.prototype.slice.call(arguments)
var str = args.shift()
var cb = function () {} // start with noop.
if (typeof args[args.length - 1] === 'function') cb = args.pop()
cb = cb || function () {} // noop.
if (!this.cache[this.locale]) this._readLocaleFile()
// we've observed a new string, update the language file.
if (!this.cache[this.locale][str] && this.updateFiles) {
this.cache[this.locale][str] = str
// include the current directory and locale,
// since these values could change before the
// write is performed.
this._enqueueWrite([this.directory, this.locale, cb])
} else {
cb()
}
return util.format.apply(util, [this.cache[this.locale][str] || str].concat(args))
}
Y18N.prototype._taggedLiteral = function (parts) {
var args = arguments
var str = ''
parts.forEach(function (part, i) {
var arg = args[i + 1]
str += part
if (typeof arg !== 'undefined') {
str += '%s'
}
})
return this.__.apply(null, [str].concat([].slice.call(arguments, 1)))
}
Y18N.prototype._enqueueWrite = function (work) {
this.writeQueue.push(work)
if (this.writeQueue.length === 1) this._processWriteQueue()
}
Y18N.prototype._processWriteQueue = function () {
var _this = this
var work = this.writeQueue[0]
// destructure the enqueued work.
var directory = work[0]
var locale = work[1]
var cb = work[2]
var languageFile = this._resolveLocaleFile(directory, locale)
var serializedLocale = JSON.stringify(this.cache[locale], null, 2)
fs.writeFile(languageFile, serializedLocale, 'utf-8', function (err) {
_this.writeQueue.shift()
if (_this.writeQueue.length > 0) _this._processWriteQueue()
cb(err)
})
}
Y18N.prototype._readLocaleFile = function () {
var localeLookup = {}
var languageFile = this._resolveLocaleFile(this.directory, this.locale)
try {
localeLookup = JSON.parse(fs.readFileSync(languageFile, 'utf-8'))
} catch (err) {
if (err instanceof SyntaxError) {
err.message = 'syntax error in ' + languageFile
}
if (err.code === 'ENOENT') localeLookup = {}
else throw err
}
this.cache[this.locale] = localeLookup
}
Y18N.prototype._resolveLocaleFile = function (directory, locale) {
var file = path.resolve(directory, './', locale + '.json')
if (this.fallbackToLanguage && !this._fileExistsSync(file) && ~locale.lastIndexOf('_')) {
// attempt fallback to language only
var languageFile = path.resolve(directory, './', locale.split('_')[0] + '.json')
if (this._fileExistsSync(languageFile)) file = languageFile
}
return file
}
// this only exists because fs.existsSync() "will be deprecated"
// see https://nodejs.org/api/fs.html#fs_fs_existssync_path
Y18N.prototype._fileExistsSync = function (file) {
try {
return fs.statSync(file).isFile()
} catch (err) {
return false
}
}
Y18N.prototype.__n = function () {
var args = Array.prototype.slice.call(arguments)
var singular = args.shift()
var plural = args.shift()
var quantity = args.shift()
var cb = function () {} // start with noop.
if (typeof args[args.length - 1] === 'function') cb = args.pop()
if (!this.cache[this.locale]) this._readLocaleFile()
var str = quantity === 1 ? singular : plural
if (this.cache[this.locale][singular]) {
str = this.cache[this.locale][singular][quantity === 1 ? 'one' : 'other']
}
// we've observed a new string, update the language file.
if (!this.cache[this.locale][singular] && this.updateFiles) {
this.cache[this.locale][singular] = {
one: singular,
other: plural
}
// include the current directory and locale,
// since these values could change before the
// write is performed.
this._enqueueWrite([this.directory, this.locale, cb])
} else {
cb()
}
// if a %d placeholder is provided, add quantity
// to the arguments expanded by util.format.
var values = [str]
if (~str.indexOf('%d')) values.push(quantity)
return util.format.apply(util, values.concat(args))
}
Y18N.prototype.setLocale = function (locale) {
this.locale = locale
}
Y18N.prototype.getLocale = function () {
return this.locale
}
Y18N.prototype.updateLocale = function (obj) {
if (!this.cache[this.locale]) this._readLocaleFile()
for (var key in obj) {
this.cache[this.locale][key] = obj[key]
}
}
module.exports = function (opts) {
var y18n = new Y18N(opts)
// bind all functions to y18n, so that
// they can be used in isolation.
for (var key in y18n) {
if (typeof y18n[key] === 'function') {
y18n[key] = y18n[key].bind(y18n)
}
}
return y18n
}

View File

@@ -0,0 +1,39 @@
{
"name": "y18n",
"version": "4.0.3",
"description": "the bare-bones internationalization library used by yargs",
"main": "index.js",
"scripts": {
"pretest": "standard",
"test": "nyc mocha",
"coverage": "nyc report --reporter=text-lcov | coveralls",
"release": "standard-version"
},
"repository": {
"type": "git",
"url": "git@github.com:yargs/y18n.git"
},
"files": [
"index.js"
],
"keywords": [
"i18n",
"internationalization",
"yargs"
],
"author": "Ben Coe <ben@npmjs.com>",
"license": "ISC",
"bugs": {
"url": "https://github.com/yargs/y18n/issues"
},
"homepage": "https://github.com/yargs/y18n",
"devDependencies": {
"chai": "^4.0.1",
"coveralls": "^3.0.0",
"mocha": "^4.0.1",
"nyc": "^11.0.1",
"rimraf": "^2.5.0",
"standard": "^10.0.0-beta.0",
"standard-version": "^4.2.0"
}
}

View File

@@ -0,0 +1,601 @@
# Changelog
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.
### [18.1.3](https://www.github.com/yargs/yargs-parser/compare/v18.1.2...v18.1.3) (2020-04-16)
### Bug Fixes
* **setArg:** options using camel-case and dot-notation populated twice ([#268](https://www.github.com/yargs/yargs-parser/issues/268)) ([f7e15b9](https://www.github.com/yargs/yargs-parser/commit/f7e15b9800900b9856acac1a830a5f35847be73e))
### [18.1.2](https://www.github.com/yargs/yargs-parser/compare/v18.1.1...v18.1.2) (2020-03-26)
### Bug Fixes
* **array, nargs:** support -o=--value and --option=--value format ([#262](https://www.github.com/yargs/yargs-parser/issues/262)) ([41d3f81](https://www.github.com/yargs/yargs-parser/commit/41d3f8139e116706b28de9b0de3433feb08d2f13))
### [18.1.1](https://www.github.com/yargs/yargs-parser/compare/v18.1.0...v18.1.1) (2020-03-16)
### Bug Fixes
* \_\_proto\_\_ will now be replaced with \_\_\_proto\_\_\_ in parse ([#258](https://www.github.com/yargs/yargs-parser/issues/258)), patching a potential
prototype pollution vulnerability. This was reported by the Snyk Security Research Team.([63810ca](https://www.github.com/yargs/yargs-parser/commit/63810ca1ae1a24b08293a4d971e70e058c7a41e2))
## [18.1.0](https://www.github.com/yargs/yargs-parser/compare/v18.0.0...v18.1.0) (2020-03-07)
### Features
* introduce single-digit boolean aliases ([#255](https://www.github.com/yargs/yargs-parser/issues/255)) ([9c60265](https://www.github.com/yargs/yargs-parser/commit/9c60265fd7a03cb98e6df3e32c8c5e7508d9f56f))
## [18.0.0](https://www.github.com/yargs/yargs-parser/compare/v17.1.0...v18.0.0) (2020-03-02)
### ⚠ BREAKING CHANGES
* the narg count is now enforced when parsing arrays.
### Features
* NaN can now be provided as a value for nargs, indicating "at least" one value is expected for array ([#251](https://www.github.com/yargs/yargs-parser/issues/251)) ([9db4be8](https://www.github.com/yargs/yargs-parser/commit/9db4be81417a2c7097128db34d86fe70ef4af70c))
## [17.1.0](https://www.github.com/yargs/yargs-parser/compare/v17.0.1...v17.1.0) (2020-03-01)
### Features
* introduce greedy-arrays config, for specifying whether arrays consume multiple positionals ([#249](https://www.github.com/yargs/yargs-parser/issues/249)) ([60e880a](https://www.github.com/yargs/yargs-parser/commit/60e880a837046314d89fa4725f923837fd33a9eb))
### [17.0.1](https://www.github.com/yargs/yargs-parser/compare/v17.0.0...v17.0.1) (2020-02-29)
### Bug Fixes
* normalized keys were not enumerable ([#247](https://www.github.com/yargs/yargs-parser/issues/247)) ([57119f9](https://www.github.com/yargs/yargs-parser/commit/57119f9f17cf27499bd95e61c2f72d18314f11ba))
## [17.0.0](https://www.github.com/yargs/yargs-parser/compare/v16.1.0...v17.0.0) (2020-02-10)
### ⚠ BREAKING CHANGES
* this reverts parsing behavior of booleans to that of yargs@14
* objects used during parsing are now created with a null
prototype. There may be some scenarios where this change in behavior
leaks externally.
### Features
* boolean arguments will not be collected into an implicit array ([#236](https://www.github.com/yargs/yargs-parser/issues/236)) ([34c4e19](https://www.github.com/yargs/yargs-parser/commit/34c4e19bae4e7af63e3cb6fa654a97ed476e5eb5))
* introduce nargs-eats-options config option ([#246](https://www.github.com/yargs/yargs-parser/issues/246)) ([d50822a](https://www.github.com/yargs/yargs-parser/commit/d50822ac10e1b05f2e9643671ca131ac251b6732))
### Bug Fixes
* address bugs with "uknown-options-as-args" ([bc023e3](https://www.github.com/yargs/yargs-parser/commit/bc023e3b13e20a118353f9507d1c999bf388a346))
* array should take precedence over nargs, but enforce nargs ([#243](https://www.github.com/yargs/yargs-parser/issues/243)) ([4cbc188](https://www.github.com/yargs/yargs-parser/commit/4cbc188b7abb2249529a19c090338debdad2fe6c))
* support keys that collide with object prototypes ([#234](https://www.github.com/yargs/yargs-parser/issues/234)) ([1587b6d](https://www.github.com/yargs/yargs-parser/commit/1587b6d91db853a9109f1be6b209077993fee4de))
* unknown options terminated with digits now handled by unknown-options-as-args ([#238](https://www.github.com/yargs/yargs-parser/issues/238)) ([d36cdfa](https://www.github.com/yargs/yargs-parser/commit/d36cdfa854254d7c7e0fe1d583818332ac46c2a5))
## [16.1.0](https://www.github.com/yargs/yargs-parser/compare/v16.0.0...v16.1.0) (2019-11-01)
### ⚠ BREAKING CHANGES
* populate error if incompatible narg/count or array/count options are used (#191)
### Features
* options that have had their default value used are now tracked ([#211](https://www.github.com/yargs/yargs-parser/issues/211)) ([a525234](https://www.github.com/yargs/yargs-parser/commit/a525234558c847deedd73f8792e0a3b77b26e2c0))
* populate error if incompatible narg/count or array/count options are used ([#191](https://www.github.com/yargs/yargs-parser/issues/191)) ([84a401f](https://www.github.com/yargs/yargs-parser/commit/84a401f0fa3095e0a19661670d1570d0c3b9d3c9))
### Reverts
* revert 16.0.0 CHANGELOG entry ([920320a](https://www.github.com/yargs/yargs-parser/commit/920320ad9861bbfd58eda39221ae211540fc1daf))
## [15.0.0](https://github.com/yargs/yargs-parser/compare/v14.0.0...v15.0.0) (2019-10-07)
### Features
* rework `collect-unknown-options` into `unknown-options-as-args`, providing more comprehensive functionality ([ef771ca](https://github.com/yargs/yargs-parser/commit/ef771ca))
### BREAKING CHANGES
* rework `collect-unknown-options` into `unknown-options-as-args`, providing more comprehensive functionality
## [14.0.0](https://github.com/yargs/yargs-parser/compare/v13.1.1...v14.0.0) (2019-09-06)
### Bug Fixes
* boolean arrays with default values ([#185](https://github.com/yargs/yargs-parser/issues/185)) ([7d42572](https://github.com/yargs/yargs-parser/commit/7d42572))
* boolean now behaves the same as other array types ([#184](https://github.com/yargs/yargs-parser/issues/184)) ([17ca3bd](https://github.com/yargs/yargs-parser/commit/17ca3bd))
* eatNargs() for 'opt.narg === 0' and boolean typed options ([#188](https://github.com/yargs/yargs-parser/issues/188)) ([c5a1db0](https://github.com/yargs/yargs-parser/commit/c5a1db0))
* maybeCoerceNumber now takes precedence over coerce return value ([#182](https://github.com/yargs/yargs-parser/issues/182)) ([2f26436](https://github.com/yargs/yargs-parser/commit/2f26436))
* take into account aliases when appending arrays from config object ([#199](https://github.com/yargs/yargs-parser/issues/199)) ([f8a2d3f](https://github.com/yargs/yargs-parser/commit/f8a2d3f))
### Features
* add configuration option to "collect-unknown-options" ([#181](https://github.com/yargs/yargs-parser/issues/181)) ([7909cc4](https://github.com/yargs/yargs-parser/commit/7909cc4))
* maybeCoerceNumber() now takes into account arrays ([#187](https://github.com/yargs/yargs-parser/issues/187)) ([31c204b](https://github.com/yargs/yargs-parser/commit/31c204b))
### BREAKING CHANGES
* unless "parse-numbers" is set to "false", arrays of numeric strings are now parsed as numbers, rather than strings.
* we have dropped the broken "defaulted" functionality; we would like to revisit adding this in the future.
* maybeCoerceNumber now takes precedence over coerce return value (#182)
### [13.1.1](https://www.github.com/yargs/yargs-parser/compare/v13.1.0...v13.1.1) (2019-06-10)
### Bug Fixes
* convert values to strings when tokenizing ([#167](https://www.github.com/yargs/yargs-parser/issues/167)) ([57b7883](https://www.github.com/yargs/yargs-parser/commit/57b7883))
* nargs should allow duplicates when duplicate-arguments-array=false ([#164](https://www.github.com/yargs/yargs-parser/issues/164)) ([47ccb0b](https://www.github.com/yargs/yargs-parser/commit/47ccb0b))
* should populate "_" when given config with "short-option-groups" false ([#179](https://www.github.com/yargs/yargs-parser/issues/179)) ([6055974](https://www.github.com/yargs/yargs-parser/commit/6055974))
## [13.1.0](https://github.com/yargs/yargs-parser/compare/v13.0.0...v13.1.0) (2019-05-05)
### Features
* add `strip-aliased` and `strip-dashed` configuration options. ([#172](https://github.com/yargs/yargs-parser/issues/172)) ([a3936aa](https://github.com/yargs/yargs-parser/commit/a3936aa))
* support boolean which do not consume next argument. ([#171](https://github.com/yargs/yargs-parser/issues/171)) ([0ae7fcb](https://github.com/yargs/yargs-parser/commit/0ae7fcb))
<a name="13.0.0"></a>
# [13.0.0](https://github.com/yargs/yargs-parser/compare/v12.0.0...v13.0.0) (2019-02-02)
### Features
* don't coerce number from string with leading '0' or '+' ([#158](https://github.com/yargs/yargs-parser/issues/158)) ([18d0fd5](https://github.com/yargs/yargs-parser/commit/18d0fd5))
### BREAKING CHANGES
* options with leading '+' or '0' now parse as strings
<a name="12.0.0"></a>
# [12.0.0](https://github.com/yargs/yargs-parser/compare/v11.1.1...v12.0.0) (2019-01-29)
### Bug Fixes
* better handling of quoted strings ([#153](https://github.com/yargs/yargs-parser/issues/153)) ([2fb71b2](https://github.com/yargs/yargs-parser/commit/2fb71b2))
### Features
* default value is now used if no right-hand value provided for numbers/strings ([#156](https://github.com/yargs/yargs-parser/issues/156)) ([5a7c46a](https://github.com/yargs/yargs-parser/commit/5a7c46a))
### BREAKING CHANGES
* a flag with no right-hand value no longer populates defaulted options with `undefined`.
* quotes at beginning and endings of strings are not removed during parsing.
<a name="11.1.1"></a>
## [11.1.1](https://github.com/yargs/yargs-parser/compare/v11.1.0...v11.1.1) (2018-11-19)
### Bug Fixes
* ensure empty string is added into argv._ ([#140](https://github.com/yargs/yargs-parser/issues/140)) ([79cda98](https://github.com/yargs/yargs-parser/commit/79cda98))
### Reverts
* make requiresArg work in conjunction with arrays ([#136](https://github.com/yargs/yargs-parser/issues/136)) ([f4a3063](https://github.com/yargs/yargs-parser/commit/f4a3063))
<a name="11.1.0"></a>
# [11.1.0](https://github.com/yargs/yargs-parser/compare/v11.0.0...v11.1.0) (2018-11-10)
### Bug Fixes
* handling of one char alias ([#139](https://github.com/yargs/yargs-parser/issues/139)) ([ee56e31](https://github.com/yargs/yargs-parser/commit/ee56e31))
### Features
* add halt-at-non-option configuration option ([#130](https://github.com/yargs/yargs-parser/issues/130)) ([a849fce](https://github.com/yargs/yargs-parser/commit/a849fce))
<a name="11.0.0"></a>
# [11.0.0](https://github.com/yargs/yargs-parser/compare/v10.1.0...v11.0.0) (2018-10-06)
### Bug Fixes
* flatten-duplicate-arrays:false for more than 2 arrays ([#128](https://github.com/yargs/yargs-parser/issues/128)) ([2bc395f](https://github.com/yargs/yargs-parser/commit/2bc395f))
* hyphenated flags combined with dot notation broke parsing ([#131](https://github.com/yargs/yargs-parser/issues/131)) ([dc788da](https://github.com/yargs/yargs-parser/commit/dc788da))
* make requiresArg work in conjunction with arrays ([#136](https://github.com/yargs/yargs-parser/issues/136)) ([77ae1d4](https://github.com/yargs/yargs-parser/commit/77ae1d4))
### Chores
* update dependencies ([6dc42a1](https://github.com/yargs/yargs-parser/commit/6dc42a1))
### Features
* also add camelCase array options ([#125](https://github.com/yargs/yargs-parser/issues/125)) ([08c0117](https://github.com/yargs/yargs-parser/commit/08c0117))
* array.type can now be provided, supporting coercion ([#132](https://github.com/yargs/yargs-parser/issues/132)) ([4b8cfce](https://github.com/yargs/yargs-parser/commit/4b8cfce))
### BREAKING CHANGES
* drops Node 4 support
* the argv object is now populated differently (correctly) when hyphens and dot notation are used in conjunction.
<a name="10.1.0"></a>
# [10.1.0](https://github.com/yargs/yargs-parser/compare/v10.0.0...v10.1.0) (2018-06-29)
### Features
* add `set-placeholder-key` configuration ([#123](https://github.com/yargs/yargs-parser/issues/123)) ([19386ee](https://github.com/yargs/yargs-parser/commit/19386ee))
<a name="10.0.0"></a>
# [10.0.0](https://github.com/yargs/yargs-parser/compare/v9.0.2...v10.0.0) (2018-04-04)
### Bug Fixes
* do not set boolean flags if not defined in `argv` ([#119](https://github.com/yargs/yargs-parser/issues/119)) ([f6e6599](https://github.com/yargs/yargs-parser/commit/f6e6599))
### BREAKING CHANGES
* `boolean` flags defined without a `default` value will now behave like other option type and won't be set in the parsed results when the user doesn't set the corresponding CLI arg.
Previous behavior:
```js
var parse = require('yargs-parser');
parse('--flag', {boolean: ['flag']});
// => { _: [], flag: true }
parse('--no-flag', {boolean: ['flag']});
// => { _: [], flag: false }
parse('', {boolean: ['flag']});
// => { _: [], flag: false }
```
New behavior:
```js
var parse = require('yargs-parser');
parse('--flag', {boolean: ['flag']});
// => { _: [], flag: true }
parse('--no-flag', {boolean: ['flag']});
// => { _: [], flag: false }
parse('', {boolean: ['flag']});
// => { _: [] } => flag not set similarly to other option type
```
<a name="9.0.2"></a>
## [9.0.2](https://github.com/yargs/yargs-parser/compare/v9.0.1...v9.0.2) (2018-01-20)
### Bug Fixes
* nargs was still aggressively consuming too many arguments ([9b28aad](https://github.com/yargs/yargs-parser/commit/9b28aad))
<a name="9.0.1"></a>
## [9.0.1](https://github.com/yargs/yargs-parser/compare/v9.0.0...v9.0.1) (2018-01-20)
### Bug Fixes
* nargs was consuming too many arguments ([4fef206](https://github.com/yargs/yargs-parser/commit/4fef206))
<a name="9.0.0"></a>
# [9.0.0](https://github.com/yargs/yargs-parser/compare/v8.1.0...v9.0.0) (2018-01-20)
### Features
* narg arguments no longer consume flag arguments ([#114](https://github.com/yargs/yargs-parser/issues/114)) ([60bb9b3](https://github.com/yargs/yargs-parser/commit/60bb9b3))
### BREAKING CHANGES
* arguments of form --foo, -abc, will no longer be consumed by nargs
<a name="8.1.0"></a>
# [8.1.0](https://github.com/yargs/yargs-parser/compare/v8.0.0...v8.1.0) (2017-12-20)
### Bug Fixes
* allow null config values ([#108](https://github.com/yargs/yargs-parser/issues/108)) ([d8b14f9](https://github.com/yargs/yargs-parser/commit/d8b14f9))
* ensure consistent parsing of dot-notation arguments ([#102](https://github.com/yargs/yargs-parser/issues/102)) ([c9bd79c](https://github.com/yargs/yargs-parser/commit/c9bd79c))
* implement [@antoniom](https://github.com/antoniom)'s fix for camel-case expansion ([3087e1d](https://github.com/yargs/yargs-parser/commit/3087e1d))
* only run coercion functions once, despite aliases. ([#76](https://github.com/yargs/yargs-parser/issues/76)) ([#103](https://github.com/yargs/yargs-parser/issues/103)) ([507aaef](https://github.com/yargs/yargs-parser/commit/507aaef))
* scientific notation circumvented bounds check ([#110](https://github.com/yargs/yargs-parser/issues/110)) ([3571f57](https://github.com/yargs/yargs-parser/commit/3571f57))
* tokenizer should ignore spaces at the beginning of the argString ([#106](https://github.com/yargs/yargs-parser/issues/106)) ([f34ead9](https://github.com/yargs/yargs-parser/commit/f34ead9))
### Features
* make combining arrays a configurable option ([#111](https://github.com/yargs/yargs-parser/issues/111)) ([c8bf536](https://github.com/yargs/yargs-parser/commit/c8bf536))
* merge array from arguments with array from config ([#83](https://github.com/yargs/yargs-parser/issues/83)) ([806ddd6](https://github.com/yargs/yargs-parser/commit/806ddd6))
<a name="8.0.0"></a>
# [8.0.0](https://github.com/yargs/yargs-parser/compare/v7.0.0...v8.0.0) (2017-10-05)
### Bug Fixes
* Ignore multiple spaces between arguments. ([#100](https://github.com/yargs/yargs-parser/issues/100)) ([d137227](https://github.com/yargs/yargs-parser/commit/d137227))
### Features
* allow configuration of prefix for boolean negation ([#94](https://github.com/yargs/yargs-parser/issues/94)) ([00bde7d](https://github.com/yargs/yargs-parser/commit/00bde7d))
* reworking how numbers are parsed ([#104](https://github.com/yargs/yargs-parser/issues/104)) ([fba00eb](https://github.com/yargs/yargs-parser/commit/fba00eb))
### BREAKING CHANGES
* strings that fail `Number.isSafeInteger()` are no longer coerced into numbers.
<a name="7.0.0"></a>
# [7.0.0](https://github.com/yargs/yargs-parser/compare/v6.0.1...v7.0.0) (2017-05-02)
### Chores
* revert populate-- logic ([#91](https://github.com/yargs/yargs-parser/issues/91)) ([6003e6d](https://github.com/yargs/yargs-parser/commit/6003e6d))
### BREAKING CHANGES
* populate-- now defaults to false.
<a name="6.0.1"></a>
## [6.0.1](https://github.com/yargs/yargs-parser/compare/v6.0.0...v6.0.1) (2017-05-01)
### Bug Fixes
* default '--' to undefined when not provided; this is closer to the array API ([#90](https://github.com/yargs/yargs-parser/issues/90)) ([4e739cc](https://github.com/yargs/yargs-parser/commit/4e739cc))
<a name="6.0.0"></a>
# [6.0.0](https://github.com/yargs/yargs-parser/compare/v4.2.1...v6.0.0) (2017-05-01)
### Bug Fixes
* environment variables should take precedence over config file ([#81](https://github.com/yargs/yargs-parser/issues/81)) ([76cee1f](https://github.com/yargs/yargs-parser/commit/76cee1f))
* parsing hints should apply for dot notation keys ([#86](https://github.com/yargs/yargs-parser/issues/86)) ([3e47d62](https://github.com/yargs/yargs-parser/commit/3e47d62))
### Chores
* upgrade to newest version of camelcase ([#87](https://github.com/yargs/yargs-parser/issues/87)) ([f1903aa](https://github.com/yargs/yargs-parser/commit/f1903aa))
### Features
* add -- option which allows arguments after the -- flag to be returned separated from positional arguments ([#84](https://github.com/yargs/yargs-parser/issues/84)) ([2572ca8](https://github.com/yargs/yargs-parser/commit/2572ca8))
* when parsing stops, we now populate "--" by default ([#88](https://github.com/yargs/yargs-parser/issues/88)) ([cd666db](https://github.com/yargs/yargs-parser/commit/cd666db))
### BREAKING CHANGES
* rather than placing arguments in "_", when parsing is stopped via "--"; we now populate an array called "--" by default.
* camelcase now requires Node 4+.
* environment variables will now override config files (args, env, config-file, config-object)
<a name="5.0.0"></a>
# [5.0.0](https://github.com/yargs/yargs-parser/compare/v4.2.1...v5.0.0) (2017-02-18)
### Bug Fixes
* environment variables should take precedence over config file ([#81](https://github.com/yargs/yargs-parser/issues/81)) ([76cee1f](https://github.com/yargs/yargs-parser/commit/76cee1f))
### BREAKING CHANGES
* environment variables will now override config files (args, env, config-file, config-object)
<a name="4.2.1"></a>
## [4.2.1](https://github.com/yargs/yargs-parser/compare/v4.2.0...v4.2.1) (2017-01-02)
### Bug Fixes
* flatten/duplicate regression ([#75](https://github.com/yargs/yargs-parser/issues/75)) ([68d68a0](https://github.com/yargs/yargs-parser/commit/68d68a0))
<a name="4.2.0"></a>
# [4.2.0](https://github.com/yargs/yargs-parser/compare/v4.1.0...v4.2.0) (2016-12-01)
### Bug Fixes
* inner objects in configs had their keys appended to top-level key when dot-notation was disabled ([#72](https://github.com/yargs/yargs-parser/issues/72)) ([0b1b5f9](https://github.com/yargs/yargs-parser/commit/0b1b5f9))
### Features
* allow multiple arrays to be provided, rather than always combining ([#71](https://github.com/yargs/yargs-parser/issues/71)) ([0f0fb2d](https://github.com/yargs/yargs-parser/commit/0f0fb2d))
<a name="4.1.0"></a>
# [4.1.0](https://github.com/yargs/yargs-parser/compare/v4.0.2...v4.1.0) (2016-11-07)
### Features
* apply coercions to default options ([#65](https://github.com/yargs/yargs-parser/issues/65)) ([c79052b](https://github.com/yargs/yargs-parser/commit/c79052b))
* handle dot notation boolean options ([#63](https://github.com/yargs/yargs-parser/issues/63)) ([02c3545](https://github.com/yargs/yargs-parser/commit/02c3545))
<a name="4.0.2"></a>
## [4.0.2](https://github.com/yargs/yargs-parser/compare/v4.0.1...v4.0.2) (2016-09-30)
### Bug Fixes
* whoops, let's make the assign not change the Object key order ([29d069a](https://github.com/yargs/yargs-parser/commit/29d069a))
<a name="4.0.1"></a>
## [4.0.1](https://github.com/yargs/yargs-parser/compare/v4.0.0...v4.0.1) (2016-09-30)
### Bug Fixes
* lodash.assign was deprecated ([#59](https://github.com/yargs/yargs-parser/issues/59)) ([5e7eb11](https://github.com/yargs/yargs-parser/commit/5e7eb11))
<a name="4.0.0"></a>
# [4.0.0](https://github.com/yargs/yargs-parser/compare/v3.2.0...v4.0.0) (2016-09-26)
### Bug Fixes
* coerce should be applied to the final objects and arrays created ([#57](https://github.com/yargs/yargs-parser/issues/57)) ([4ca69da](https://github.com/yargs/yargs-parser/commit/4ca69da))
### BREAKING CHANGES
* coerce is no longer applied to individual arguments in an implicit array.
<a name="3.2.0"></a>
# [3.2.0](https://github.com/yargs/yargs-parser/compare/v3.1.0...v3.2.0) (2016-08-13)
### Features
* coerce full array instead of each element ([#51](https://github.com/yargs/yargs-parser/issues/51)) ([cc4dc56](https://github.com/yargs/yargs-parser/commit/cc4dc56))
<a name="3.1.0"></a>
# [3.1.0](https://github.com/yargs/yargs-parser/compare/v3.0.0...v3.1.0) (2016-08-09)
### Bug Fixes
* address pkgConf parsing bug outlined in [#37](https://github.com/yargs/yargs-parser/issues/37) ([#45](https://github.com/yargs/yargs-parser/issues/45)) ([be76ee6](https://github.com/yargs/yargs-parser/commit/be76ee6))
* better parsing of negative values ([#44](https://github.com/yargs/yargs-parser/issues/44)) ([2e43692](https://github.com/yargs/yargs-parser/commit/2e43692))
* check aliases when guessing defaults for arguments fixes [#41](https://github.com/yargs/yargs-parser/issues/41) ([#43](https://github.com/yargs/yargs-parser/issues/43)) ([f3e4616](https://github.com/yargs/yargs-parser/commit/f3e4616))
### Features
* added coerce option, for providing specialized argument parsing ([#42](https://github.com/yargs/yargs-parser/issues/42)) ([7b49cd2](https://github.com/yargs/yargs-parser/commit/7b49cd2))
<a name="3.0.0"></a>
# [3.0.0](https://github.com/yargs/yargs-parser/compare/v2.4.1...v3.0.0) (2016-08-07)
### Bug Fixes
* parsing issue with numeric character in group of options ([#19](https://github.com/yargs/yargs-parser/issues/19)) ([f743236](https://github.com/yargs/yargs-parser/commit/f743236))
* upgraded lodash.assign ([5d7fdf4](https://github.com/yargs/yargs-parser/commit/5d7fdf4))
### BREAKING CHANGES
* subtle change to how values are parsed in a group of single-character arguments.
* _first released in 3.1.0, better handling of negative values should be considered a breaking change._
<a name="2.4.1"></a>
## [2.4.1](https://github.com/yargs/yargs-parser/compare/v2.4.0...v2.4.1) (2016-07-16)
### Bug Fixes
* **count:** do not increment a default value ([#39](https://github.com/yargs/yargs-parser/issues/39)) ([b04a189](https://github.com/yargs/yargs-parser/commit/b04a189))
<a name="2.4.0"></a>
# [2.4.0](https://github.com/yargs/yargs-parser/compare/v2.3.0...v2.4.0) (2016-04-11)
### Features
* **environment:** Support nested options in environment variables ([#26](https://github.com/yargs/yargs-parser/issues/26)) thanks [@elas7](https://github.com/elas7) \o/ ([020778b](https://github.com/yargs/yargs-parser/commit/020778b))
<a name="2.3.0"></a>
# [2.3.0](https://github.com/yargs/yargs-parser/compare/v2.2.0...v2.3.0) (2016-04-09)
### Bug Fixes
* **boolean:** fix for boolean options with non boolean defaults (#20) ([2dbe86b](https://github.com/yargs/yargs-parser/commit/2dbe86b)), closes [(#20](https://github.com/(/issues/20)
* **package:** remove tests from tarball ([0353c0d](https://github.com/yargs/yargs-parser/commit/0353c0d))
* **parsing:** handle calling short option with an empty string as the next value. ([a867165](https://github.com/yargs/yargs-parser/commit/a867165))
* boolean flag when next value contains the strings 'true' or 'false'. ([69941a6](https://github.com/yargs/yargs-parser/commit/69941a6))
* update dependencies; add standard-version bin for next release (#24) ([822d9d5](https://github.com/yargs/yargs-parser/commit/822d9d5))
### Features
* **configuration:** Allow to pass configuration objects to yargs-parser ([0780900](https://github.com/yargs/yargs-parser/commit/0780900))
* **normalize:** allow normalize to work with arrays ([e0eaa1a](https://github.com/yargs/yargs-parser/commit/e0eaa1a))

View File

@@ -0,0 +1,14 @@
Copyright (c) 2016, Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,449 @@
# yargs-parser
[![Build Status](https://travis-ci.org/yargs/yargs-parser.svg)](https://travis-ci.org/yargs/yargs-parser)
[![NPM version](https://img.shields.io/npm/v/yargs-parser.svg)](https://www.npmjs.com/package/yargs-parser)
[![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version)
The mighty option parser used by [yargs](https://github.com/yargs/yargs).
visit the [yargs website](http://yargs.js.org/) for more examples, and thorough usage instructions.
<img width="250" src="https://raw.githubusercontent.com/yargs/yargs-parser/master/yargs-logo.png">
## Example
```sh
npm i yargs-parser --save
```
```js
var argv = require('yargs-parser')(process.argv.slice(2))
console.log(argv)
```
```sh
node example.js --foo=33 --bar hello
{ _: [], foo: 33, bar: 'hello' }
```
_or parse a string!_
```js
var argv = require('yargs-parser')('--foo=99 --bar=33')
console.log(argv)
```
```sh
{ _: [], foo: 99, bar: 33 }
```
Convert an array of mixed types before passing to `yargs-parser`:
```js
var parse = require('yargs-parser')
parse(['-f', 11, '--zoom', 55].join(' ')) // <-- array to string
parse(['-f', 11, '--zoom', 55].map(String)) // <-- array of strings
```
## API
### require('yargs-parser')(args, opts={})
Parses command line arguments returning a simple mapping of keys and values.
**expects:**
* `args`: a string or array of strings representing the options to parse.
* `opts`: provide a set of hints indicating how `args` should be parsed:
* `opts.alias`: an object representing the set of aliases for a key: `{alias: {foo: ['f']}}`.
* `opts.array`: indicate that keys should be parsed as an array: `{array: ['foo', 'bar']}`.<br>
Indicate that keys should be parsed as an array and coerced to booleans / numbers:<br>
`{array: [{ key: 'foo', boolean: true }, {key: 'bar', number: true}]}`.
* `opts.boolean`: arguments should be parsed as booleans: `{boolean: ['x', 'y']}`.
* `opts.coerce`: provide a custom synchronous function that returns a coerced value from the argument provided
(or throws an error). For arrays the function is called only once for the entire array:<br>
`{coerce: {foo: function (arg) {return modifiedArg}}}`.
* `opts.config`: indicate a key that represents a path to a configuration file (this file will be loaded and parsed).
* `opts.configObjects`: configuration objects to parse, their properties will be set as arguments:<br>
`{configObjects: [{'x': 5, 'y': 33}, {'z': 44}]}`.
* `opts.configuration`: provide configuration options to the yargs-parser (see: [configuration](#configuration)).
* `opts.count`: indicate a key that should be used as a counter, e.g., `-vvv` = `{v: 3}`.
* `opts.default`: provide default values for keys: `{default: {x: 33, y: 'hello world!'}}`.
* `opts.envPrefix`: environment variables (`process.env`) with the prefix provided should be parsed.
* `opts.narg`: specify that a key requires `n` arguments: `{narg: {x: 2}}`.
* `opts.normalize`: `path.normalize()` will be applied to values set to this key.
* `opts.number`: keys should be treated as numbers.
* `opts.string`: keys should be treated as strings (even if they resemble a number `-x 33`).
**returns:**
* `obj`: an object representing the parsed value of `args`
* `key/value`: key value pairs for each argument and their aliases.
* `_`: an array representing the positional arguments.
* [optional] `--`: an array with arguments after the end-of-options flag `--`.
### require('yargs-parser').detailed(args, opts={})
Parses a command line string, returning detailed information required by the
yargs engine.
**expects:**
* `args`: a string or array of strings representing options to parse.
* `opts`: provide a set of hints indicating how `args`, inputs are identical to `require('yargs-parser')(args, opts={})`.
**returns:**
* `argv`: an object representing the parsed value of `args`
* `key/value`: key value pairs for each argument and their aliases.
* `_`: an array representing the positional arguments.
* [optional] `--`: an array with arguments after the end-of-options flag `--`.
* `error`: populated with an error object if an exception occurred during parsing.
* `aliases`: the inferred list of aliases built by combining lists in `opts.alias`.
* `newAliases`: any new aliases added via camel-case expansion:
* `boolean`: `{ fooBar: true }`
* `defaulted`: any new argument created by `opts.default`, no aliases included.
* `boolean`: `{ foo: true }`
* `configuration`: given by default settings and `opts.configuration`.
<a name="configuration"></a>
### Configuration
The yargs-parser applies several automated transformations on the keys provided
in `args`. These features can be turned on and off using the `configuration` field
of `opts`.
```js
var parsed = parser(['--no-dice'], {
configuration: {
'boolean-negation': false
}
})
```
### short option groups
* default: `true`.
* key: `short-option-groups`.
Should a group of short-options be treated as boolean flags?
```sh
node example.js -abc
{ _: [], a: true, b: true, c: true }
```
_if disabled:_
```sh
node example.js -abc
{ _: [], abc: true }
```
### camel-case expansion
* default: `true`.
* key: `camel-case-expansion`.
Should hyphenated arguments be expanded into camel-case aliases?
```sh
node example.js --foo-bar
{ _: [], 'foo-bar': true, fooBar: true }
```
_if disabled:_
```sh
node example.js --foo-bar
{ _: [], 'foo-bar': true }
```
### dot-notation
* default: `true`
* key: `dot-notation`
Should keys that contain `.` be treated as objects?
```sh
node example.js --foo.bar
{ _: [], foo: { bar: true } }
```
_if disabled:_
```sh
node example.js --foo.bar
{ _: [], "foo.bar": true }
```
### parse numbers
* default: `true`
* key: `parse-numbers`
Should keys that look like numbers be treated as such?
```sh
node example.js --foo=99.3
{ _: [], foo: 99.3 }
```
_if disabled:_
```sh
node example.js --foo=99.3
{ _: [], foo: "99.3" }
```
### boolean negation
* default: `true`
* key: `boolean-negation`
Should variables prefixed with `--no` be treated as negations?
```sh
node example.js --no-foo
{ _: [], foo: false }
```
_if disabled:_
```sh
node example.js --no-foo
{ _: [], "no-foo": true }
```
### combine arrays
* default: `false`
* key: `combine-arrays`
Should arrays be combined when provided by both command line arguments and
a configuration file.
### duplicate arguments array
* default: `true`
* key: `duplicate-arguments-array`
Should arguments be coerced into an array when duplicated:
```sh
node example.js -x 1 -x 2
{ _: [], x: [1, 2] }
```
_if disabled:_
```sh
node example.js -x 1 -x 2
{ _: [], x: 2 }
```
### flatten duplicate arrays
* default: `true`
* key: `flatten-duplicate-arrays`
Should array arguments be coerced into a single array when duplicated:
```sh
node example.js -x 1 2 -x 3 4
{ _: [], x: [1, 2, 3, 4] }
```
_if disabled:_
```sh
node example.js -x 1 2 -x 3 4
{ _: [], x: [[1, 2], [3, 4]] }
```
### greedy arrays
* default: `true`
* key: `greedy-arrays`
Should arrays consume more than one positional argument following their flag.
```sh
node example --arr 1 2
{ _[], arr: [1, 2] }
```
_if disabled:_
```sh
node example --arr 1 2
{ _[2], arr: [1] }
```
**Note: in `v18.0.0` we are considering defaulting greedy arrays to `false`.**
### nargs eats options
* default: `false`
* key: `nargs-eats-options`
Should nargs consume dash options as well as positional arguments.
### negation prefix
* default: `no-`
* key: `negation-prefix`
The prefix to use for negated boolean variables.
```sh
node example.js --no-foo
{ _: [], foo: false }
```
_if set to `quux`:_
```sh
node example.js --quuxfoo
{ _: [], foo: false }
```
### populate --
* default: `false`.
* key: `populate--`
Should unparsed flags be stored in `--` or `_`.
_If disabled:_
```sh
node example.js a -b -- x y
{ _: [ 'a', 'x', 'y' ], b: true }
```
_If enabled:_
```sh
node example.js a -b -- x y
{ _: [ 'a' ], '--': [ 'x', 'y' ], b: true }
```
### set placeholder key
* default: `false`.
* key: `set-placeholder-key`.
Should a placeholder be added for keys not set via the corresponding CLI argument?
_If disabled:_
```sh
node example.js -a 1 -c 2
{ _: [], a: 1, c: 2 }
```
_If enabled:_
```sh
node example.js -a 1 -c 2
{ _: [], a: 1, b: undefined, c: 2 }
```
### halt at non-option
* default: `false`.
* key: `halt-at-non-option`.
Should parsing stop at the first positional argument? This is similar to how e.g. `ssh` parses its command line.
_If disabled:_
```sh
node example.js -a run b -x y
{ _: [ 'b' ], a: 'run', x: 'y' }
```
_If enabled:_
```sh
node example.js -a run b -x y
{ _: [ 'b', '-x', 'y' ], a: 'run' }
```
### strip aliased
* default: `false`
* key: `strip-aliased`
Should aliases be removed before returning results?
_If disabled:_
```sh
node example.js --test-field 1
{ _: [], 'test-field': 1, testField: 1, 'test-alias': 1, testAlias: 1 }
```
_If enabled:_
```sh
node example.js --test-field 1
{ _: [], 'test-field': 1, testField: 1 }
```
### strip dashed
* default: `false`
* key: `strip-dashed`
Should dashed keys be removed before returning results? This option has no effect if
`camel-case-expansion` is disabled.
_If disabled:_
```sh
node example.js --test-field 1
{ _: [], 'test-field': 1, testField: 1 }
```
_If enabled:_
```sh
node example.js --test-field 1
{ _: [], testField: 1 }
```
### unknown options as args
* default: `false`
* key: `unknown-options-as-args`
Should unknown options be treated like regular arguments? An unknown option is one that is not
configured in `opts`.
_If disabled_
```sh
node example.js --unknown-option --known-option 2 --string-option --unknown-option2
{ _: [], unknownOption: true, knownOption: 2, stringOption: '', unknownOption2: true }
```
_If enabled_
```sh
node example.js --unknown-option --known-option 2 --string-option --unknown-option2
{ _: ['--unknown-option'], knownOption: 2, stringOption: '--unknown-option2' }
```
## Special Thanks
The yargs project evolves from optimist and minimist. It owes its
existence to a lot of James Halliday's hard work. Thanks [substack](https://github.com/substack) **beep** **boop** \o/
## License
ISC

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
// take an un-split argv string and tokenize it.
module.exports = function (argString) {
if (Array.isArray(argString)) {
return argString.map(e => typeof e !== 'string' ? e + '' : e)
}
argString = argString.trim()
let i = 0
let prevC = null
let c = null
let opening = null
const args = []
for (let ii = 0; ii < argString.length; ii++) {
prevC = c
c = argString.charAt(ii)
// split on spaces unless we're in quotes.
if (c === ' ' && !opening) {
if (!(prevC === ' ')) {
i++
}
continue
}
// don't split the string if we're in matching
// opening or closing single and double quotes.
if (c === opening) {
opening = null
} else if ((c === "'" || c === '"') && !opening) {
opening = c
}
if (!args[i]) args[i] = ''
args[i] += c
}
return args
}

View File

@@ -0,0 +1,46 @@
{
"name": "yargs-parser",
"version": "18.1.3",
"description": "the mighty option parser used by yargs",
"main": "index.js",
"scripts": {
"fix": "standard --fix",
"test": "c8 --reporter=text --reporter=html mocha test/*.js",
"posttest": "standard",
"coverage": "c8 report --check-coverage check-coverage --lines=100 --branches=97 --statements=100"
},
"repository": {
"type": "git",
"url": "https://github.com/yargs/yargs-parser.git"
},
"keywords": [
"argument",
"parser",
"yargs",
"command",
"cli",
"parsing",
"option",
"args",
"argument"
],
"author": "Ben Coe <ben@npmjs.com>",
"license": "ISC",
"devDependencies": {
"c8": "^7.0.1",
"chai": "^4.2.0",
"mocha": "^7.0.0",
"standard": "^14.3.1"
},
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
},
"files": [
"lib",
"index.js"
],
"engines": {
"node": ">=6"
}
}

Some files were not shown because too many files have changed in this diff Show More