mirror of
https://github.com/faisalman/ua-parser-js.git
synced 2025-11-15 14:42:16 +03:00
[feat] Add new CLI feature: processing batch user-agent data from file and output as JSON
This commit is contained in:
@@ -23,8 +23,12 @@
|
|||||||
- **Support for Custom/Predefined Extensions:**
|
- **Support for Custom/Predefined Extensions:**
|
||||||
- Pass custom regexes or predefined extensions as a list to `UAParser()`
|
- Pass custom regexes or predefined extensions as a list to `UAParser()`
|
||||||
|
|
||||||
- **Support for CLI Parsing:**
|
- **Support for CLI Processing:**
|
||||||
- Parse a user-agent directly from the command line using `npx ua-parser-js "[User-Agent]"`
|
- Directly parse user-agent strings from the command line:
|
||||||
|
`npx ua-parser-js "<User-Agent>"`
|
||||||
|
- Process batch data from files:
|
||||||
|
`npx ua-parser-js --input-file=log.txt >> result.json` or
|
||||||
|
`npx ua-parser-js --input-file=log.txt --output-file=result.json`
|
||||||
|
|
||||||
- **Enhanced Detection with Client Hints:**
|
- **Enhanced Detection with Client Hints:**
|
||||||
- `withClientHints()`: Improves detection accuracy by leveraging client hints
|
- `withClientHints()`: Improves detection accuracy by leveraging client hints
|
||||||
|
|||||||
@@ -220,7 +220,7 @@
|
|||||||
"test:eslint": "eslint src && eslint script",
|
"test:eslint": "eslint src && eslint script",
|
||||||
"test:jshint": "jshint src/main",
|
"test:jshint": "jshint src/main",
|
||||||
"test:lockfile-lint": "npx lockfile-lint -p package-lock.json",
|
"test:lockfile-lint": "npx lockfile-lint -p package-lock.json",
|
||||||
"test:mocha": "mocha test/unit",
|
"test:mocha": "mocha --recursive test/unit",
|
||||||
"test:playwright": "npx playwright install && playwright test test/e2e --browser all"
|
"test:playwright": "npx playwright install && playwright test test/e2e --browser all"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,4 +1,94 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
const { performance } = require('node:perf_hooks');
|
||||||
|
const readline = require('node:readline');
|
||||||
|
const { parseArgs } = require('node:util');
|
||||||
const UAParser = require('ua-parser-js');
|
const UAParser = require('ua-parser-js');
|
||||||
console.log(JSON.stringify(process.argv.slice(2).map(ua => UAParser(ua)), null, 4));
|
const { Bots, Emails, ExtraDevices, InApps, Vehicles } = require('ua-parser-js/extensions');
|
||||||
|
|
||||||
|
if (!process.argv[2].startsWith('-')) {
|
||||||
|
|
||||||
|
const results = process.argv.slice(2).map(ua => UAParser(ua));
|
||||||
|
console.log(JSON.stringify(results, null, 4));
|
||||||
|
process.exit(0);
|
||||||
|
|
||||||
|
} else if (['-h', '--help'].includes(process.argv[2])) {
|
||||||
|
|
||||||
|
console.log('Usage: npx ua-parser-js <string>');
|
||||||
|
console.log(' or npx ua-parser-js --input-file <filepath> [--output-file <filepath>]');
|
||||||
|
console.log('-i, --input-file');
|
||||||
|
console.log('-o, --output-file');
|
||||||
|
process.exit(0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
const startPerf = performance.now();
|
||||||
|
const {
|
||||||
|
values: {
|
||||||
|
'input-file': inputFile,
|
||||||
|
'output-file': outputFile
|
||||||
|
},
|
||||||
|
} = parseArgs({
|
||||||
|
options: {
|
||||||
|
'input-file': { type: 'string', short: 'i' },
|
||||||
|
'output-file': { type: 'string', short: 'o' }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!inputFile) {
|
||||||
|
console.error('Input file must be present');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputPath = path.resolve(__dirname, inputFile);
|
||||||
|
const outputPath = outputFile ? path.resolve(__dirname, outputFile) : null;
|
||||||
|
|
||||||
|
if (!fs.existsSync(inputPath)) {
|
||||||
|
console.error(`Input file not found: ${inputPath}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputStream = fs.createReadStream(inputPath, 'utf8');
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: inputStream,
|
||||||
|
crlfDelay: Infinity
|
||||||
|
});
|
||||||
|
|
||||||
|
const outputStream = outputPath ? fs.createWriteStream(outputPath, { encoding : 'utf8' }) : process.stdout;
|
||||||
|
|
||||||
|
const uap = new UAParser([Bots, Emails, ExtraDevices, InApps, Vehicles]);
|
||||||
|
let lineNumber = 0;
|
||||||
|
|
||||||
|
outputStream.write('[\n');
|
||||||
|
|
||||||
|
rl.on('line', line => {
|
||||||
|
const result = uap.setUA(line).getResult();
|
||||||
|
const json = JSON.stringify(result, null, 4);
|
||||||
|
if (lineNumber > 0) outputStream.write(',\n');
|
||||||
|
outputStream.write(json);
|
||||||
|
lineNumber++;
|
||||||
|
});
|
||||||
|
|
||||||
|
rl.on('close', () => {
|
||||||
|
outputStream.write('\n]');
|
||||||
|
if (outputPath) {
|
||||||
|
outputStream.end(() => {
|
||||||
|
const finishPerf = performance.now();
|
||||||
|
console.log(`Done!`);
|
||||||
|
console.log(`Number of lines found: ${lineNumber}`);
|
||||||
|
console.log(`Task finished in: ${(finishPerf - startPerf).toFixed(3)}ms`);
|
||||||
|
console.log(`Output written to: ${outputPath}`);
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
37
test/unit/cli/cli.spec.js
Normal file
37
test/unit/cli/cli.spec.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
const assert = require('node:assert');
|
||||||
|
const { exec } = require('node:child_process');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const { UAParser } = require('../../../src/main/ua-parser');
|
||||||
|
const uap = new UAParser();
|
||||||
|
|
||||||
|
describe('npx ua-parser-js <string>', () => {
|
||||||
|
it ('print result to stdout', () => {
|
||||||
|
exec('npx ua-parser-js "TEST"', (err, stdout, stderr) => {
|
||||||
|
assert.deepEqual(JSON.parse(stdout), JSON.parse(JSON.stringify([uap.setUA("TEST").getResult()])));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('npx ua-parser-js --input-file=<filepath>', () => {
|
||||||
|
it ('load file and print result to stdout', () => {
|
||||||
|
exec('npx ua-parser-js --input-file="../test/unit/cli/input.txt"', (err, stdout, stderr) => {
|
||||||
|
assert.deepEqual(JSON.parse(stdout), JSON.parse(JSON.stringify([
|
||||||
|
uap.setUA('Opera/9.25 (Windows NT 6.0; U; ru)').getResult(),
|
||||||
|
uap.setUA('Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)').getResult()
|
||||||
|
])));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('npx ua-parser-js --input-file=<filepath> --output-file=<filepath>', () => {
|
||||||
|
it ('load file and save result to file', () => {
|
||||||
|
exec('npx ua-parser-js --input-file="../test/unit/cli/input.txt" --output-file="../test/unit/cli/output.json"', (err, stdout, stderr) => {
|
||||||
|
fs.readFile('test/unit/cli/output.json', (err, data) => {
|
||||||
|
assert.deepEqual(JSON.parse(data), JSON.parse(JSON.stringify([
|
||||||
|
uap.setUA('Opera/9.25 (Windows NT 6.0; U; ru)').getResult(),
|
||||||
|
uap.setUA('Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)').getResult()
|
||||||
|
])));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
2
test/unit/cli/input.txt
Normal file
2
test/unit/cli/input.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Opera/9.25 (Windows NT 6.0; U; ru)
|
||||||
|
Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)
|
||||||
32
test/unit/cli/output.json
Normal file
32
test/unit/cli/output.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"ua": "Opera/9.25 (Windows NT 6.0; U; ru)",
|
||||||
|
"browser": {
|
||||||
|
"name": "Opera",
|
||||||
|
"version": "9.25",
|
||||||
|
"major": "9"
|
||||||
|
},
|
||||||
|
"cpu": {},
|
||||||
|
"device": {},
|
||||||
|
"engine": {},
|
||||||
|
"os": {
|
||||||
|
"name": "Windows",
|
||||||
|
"version": "Vista"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ua": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)",
|
||||||
|
"browser": {
|
||||||
|
"name": "IE",
|
||||||
|
"version": "5.5",
|
||||||
|
"major": "5"
|
||||||
|
},
|
||||||
|
"cpu": {},
|
||||||
|
"device": {},
|
||||||
|
"engine": {},
|
||||||
|
"os": {
|
||||||
|
"name": "Windows",
|
||||||
|
"version": "NT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user