Skip to content

Commit

Permalink
feat: Convert codebase to TypeScript and add some types
Browse files Browse the repository at this point in the history
  • Loading branch information
lili2311 committed Apr 28, 2019
1 parent 95b5369 commit b1114a3
Show file tree
Hide file tree
Showing 14 changed files with 303 additions and 271 deletions.
30 changes: 11 additions & 19 deletions lib/index.js → lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
var parse = require('./parse-mvn');
var fs = require('fs');
var path = require('path');
var subProcess = require('./sub-process');
import {parseTree} from './parse-mvn';
import * as fs from 'fs';
import * as path from 'path';
import * as subProcess from './sub-process';

module.exports = {
inspect: inspect,
};

module.exports.__tests = {
buildArgs: buildArgs,
};

function inspect(root, targetFile, options) {
export function inspect(root, targetFile, options) {
if (!options) {
options = {dev: false};
}
var mvnArgs = buildArgs(root, targetFile, options.args);
const mvnArgs = buildArgs(root, targetFile, options.args);
return subProcess.execute('mvn', mvnArgs, {cwd: root})
.then(function(result) {
var parseResult = parse(result, options.dev);
.then((result) => {
const parseResult = parseTree(result, options.dev);
return {
plugin: {
name: 'bundled:maven',
Expand All @@ -27,7 +19,7 @@ function inspect(root, targetFile, options) {
package: parseResult.data,
};
})
.catch(function(error) {
.catch((error) => {
error.message = error.message + '\n\n' +
'Please make sure that Apache Maven Dependency Plugin ' +
'version 2.2 or above is installed, and that ' +
Expand All @@ -39,9 +31,9 @@ function inspect(root, targetFile, options) {
});
}

function buildArgs(root, targetFile, mavenArgs) {
export function buildArgs(root, targetFile, mavenArgs) {
// Requires Maven >= 2.2
var args = ['dependency:tree', '-DoutputType=dot'];
let args = ['dependency:tree', '-DoutputType=dot'];
if (targetFile) {
if (!fs.existsSync(path.resolve(root, targetFile))) {
throw new Error('File not found: "' + targetFile + '"');
Expand Down
112 changes: 0 additions & 112 deletions lib/parse-mvn.js

This file was deleted.

126 changes: 126 additions & 0 deletions lib/parse-mvn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {DepTree} from './types';
import * as _ from 'lodash';

const newline = /[\r\n]+/g;
const logLabel = /^\[\w+\]\s*/gm;
const digraph = /digraph([\s\S]*?)\}/g;
const errorLabel = /^\[ERROR\]/gm;

// Parse the output from 'mvn dependency:tree -DoutputType=dot'
export function parseTree(text, withDev) {
// check for errors in mvn output
if (errorLabel.test(text)) {
throw new Error('Failed to execute an `mvn` command.');
}

// clear all labels
text = text.replace(logLabel, '');

// extract deps
const data = getRootProject(text, withDev);

return {ok: true, data};
}

function getRootProject(text, withDev) {
const projects = text.match(digraph);
if (!projects) {
throw new Error('Cannot find dependency information.');
}
const rootProject = getProject(projects[0], withDev);
const defaultRoot: DepTree = {
name: 'no-name',
version: '0.0.0',
dependencies: {},
packageFormatVersion: 'mvn:0.0.1',
};

const root = {
...defaultRoot,
...rootProject,
};

// Add any subsequent projects to the root as dependencies
for (let i = 1; i < projects.length; i++) {
const project: DepTree | null = getProject(projects[i], withDev);
if (project && project.name) {
root.dependencies = {};
root.dependencies[project.name] = project;
}
}
return root;
}

function getProject(projectDump, withDev) {
const lines = projectDump.split(newline);
const identity = dequote(lines[0]);
const deps = {};
for (let i = 1; i < lines.length - 1; i++) {
const line = lines[i];
const nodes = line.trim().split('->');
const source = dequote(nodes[0]);
const target = dequote(nodes[1]);
deps[source] = deps[source] || [];
deps[source].push(target);
}
return assemblePackage(identity, deps, withDev);
}

function assemblePackage(source, projectDeps, withDev): DepTree | null {
const sourcePackage: DepTree = createPackage(source);
if (sourcePackage.scope === 'test' && !withDev) {
// skip a test dependency if it's not asked for
return null;
}
const sourceDeps = projectDeps[source];
if (sourceDeps) {
sourcePackage.dependencies = {};
for (const dep of sourceDeps) {
const pkg: DepTree | null = assemblePackage(
dep, projectDeps, withDev);
if (pkg) {
sourcePackage.dependencies[pkg.name] = pkg;
}
}
}
return sourcePackage;
}

function createPackage(pkgStr) {
const range = getConstraint(pkgStr);

if (range) {
pkgStr = pkgStr.substring(0, pkgStr.indexOf(' '));
}

const parts = pkgStr.split(':');
const result: DepTree = {
version: parts[3],
name: parts[0] + ':' + parts[1],
dependencies: {},
};

if (parts.length >= 5) {
result.scope = parts[parts.length - 1];
result.version = parts[parts.length - 2];
}

// TODO: This is likely obsolete, remove
if (range) {
result.dep = range;
}

return result;
}

function dequote(str) {
return str.slice(str.indexOf('"') + 1, str.lastIndexOf('"'));
}

function getConstraint(str) {
const index = str.indexOf('selected from constraint');
if (index === -1) {
return null;
}
return str.slice(index + 25, str.lastIndexOf(')'));
}
28 changes: 0 additions & 28 deletions lib/sub-process.js

This file was deleted.

31 changes: 31 additions & 0 deletions lib/sub-process.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as childProcess from 'child_process';

export function execute(command, args, options) {
const spawnOptions: {
shell: boolean;
cwd?: string;
} = {shell: true};
if (options && options.cwd) {
spawnOptions.cwd = options.cwd;
}

return new Promise((resolve, reject) => {
let stdout = '';
let stderr = '';

const proc = childProcess.spawn(command, args, spawnOptions);
proc.stdout.on('data', (data) => {
stdout = stdout + data;
});
proc.stderr.on('data', (data) => {
stderr = stderr + data;
});

proc.on('close', (code) => {
if (code !== 0) {
return reject(new Error(stdout || stderr));
}
resolve(stdout || stderr);
});
});
}
25 changes: 25 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

export interface PluginMetadata {
name: string;
runtime: string;
targetFile?: string;
}

export interface DepDict {
[name: string]: DepTree;
}

export interface DepRoot {
depTree: DepTree;
targetFile?: string;

meta?: any;
}
export interface DepTree {
name: string;
version: string;
dependencies?: DepDict;
packageFormatVersion?: string;
scope?: string; // TODO: is it needed on the Tree?
dep?: string; // TODO: is it needed on the Tree?
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"build": "tsc",
"lint": "tslint --project tsconfig.json --format stylish",
"prepare": "npm run build",
"test": "npm run lint && npm run test-functional && npm run test-system",
"test": "npm run prepare && npm run lint && npm run test-functional && npm run test-system",
"test-functional": "tap -R spec ./test/functional/*.test.[tj]s",
"test-system": "tap -R spec --timeout=180 ./test/system/*.test.[tj]s",
"semantic-release": "semantic-release"
Expand All @@ -33,6 +33,7 @@
"tslint": "5.16.0"
},
"dependencies": {
"lodash": "4.17.11",
"tslib": "1.9.3"
}
}
Loading

0 comments on commit b1114a3

Please sign in to comment.