Skip to content

Commit

Permalink
feat: add package.json parser #20
Browse files Browse the repository at this point in the history
  • Loading branch information
regevbr committed Apr 22, 2020
1 parent 6fd6508 commit f41ff63
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 28 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"moment": "~2.24.0",
"pacote": "~11.1.4",
"reflect-metadata": "~0.1.13",
"regex-parser": "^2.2.10",
"shell-quote": "^1.7.2",
"simple-git": "~1.132.0",
"sqlite3": "~4.1.1",
Expand Down
62 changes: 34 additions & 28 deletions src/utils/packageJsonParser/impl/packageJsonParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ILogger } from '../../logger/interfaces/ILogger';
import { Dependency, DependencyType, IPackageJsonData, IPackageJsonParseOptions, IPackageJsonParser } from '..';
import * as path from 'path';
import { Manifest } from 'pacote';
import { IPredicate } from '../../predicateBuilder/predicateBuilder';

const PKG_FILE = `package.json`;

Expand All @@ -17,18 +18,18 @@ export class PackageJsonParser extends IPackageJsonParser {
this.logger = loggerFactory.getLogger(`Package Json Parser`);
}

public async parse({ cwd, include }: IPackageJsonParseOptions): Promise<IPackageJsonData> {
public async parse({ cwd, include, predicate }: IPackageJsonParseOptions): Promise<IPackageJsonData> {
this.logger.info(`Reading package.json information`);
const pgkFilePath = path.join(cwd, PKG_FILE);
this.logger.debug(`Reading file`, pgkFilePath);
const content = await this.fs.promises.readFile(pgkFilePath, `utf-8`);
const pkg: Manifest = JSON.parse(content);
const dependencies = new Set<Dependency>();
// handle filtering
this.handleDepType(include.dev, pkg.devDependencies, DependencyType.DEV, dependencies, `dev`);
this.handleDepType(include.prod, pkg.dependencies, DependencyType.PROD, dependencies, `production`);
this.handleDepType(include.peer, pkg.peerDependencies, DependencyType.PEER, dependencies, `peer`);
this.handleDepType(include.optional, pkg.optionalDependencies, DependencyType.OPTIONAL, dependencies, `optional`);
const depTypeHandler = this.getDepTypeHandler(dependencies, predicate);
depTypeHandler(include.dev, pkg.devDependencies, DependencyType.DEV, `dev`);
depTypeHandler(include.prod, pkg.dependencies, DependencyType.PROD, `production`);
depTypeHandler(include.peer, pkg.peerDependencies, DependencyType.PEER, `peer`);
depTypeHandler(include.optional, pkg.optionalDependencies, DependencyType.OPTIONAL, `optional`);
const scripts = pkg.scripts || {};
this.logger.info(`Going to check ${dependencies.size} dependencies`);
return {
Expand All @@ -37,30 +38,35 @@ export class PackageJsonParser extends IPackageJsonParser {
};
}

private handleDepType(
included: boolean,
list: undefined | Record<string, string>,
type: DependencyType,
deps: Set<Dependency>,
typeStr: string,
): void {
if (included) {
if (list) {
let count = 0;
for (const [name, semver] of Object.entries(list)) {
count++;
deps.add({
name,
semver,
dependencyType: type,
});
private getDepTypeHandler(deps: Set<Dependency>, predicate: IPredicate) {
return (
included: boolean,
list: undefined | Record<string, string>,
type: DependencyType,
typeStr: string
): void => {
if (included) {
if (list) {
let count = 0;
for (const [name, semver] of Object.entries(list)) {
if (predicate(name)) {
count++;
deps.add({
name,
semver,
dependencyType: type,
});
} else {
this.logger.info(`Skipping ${name}`);
}
}
this.logger.info(`Found ${count} ${typeStr} dependencies`);
} else {
this.logger.info(`No ${typeStr} dependencies defined`);
}
this.logger.info(`Found ${count} ${typeStr} dependencies`);
} else {
this.logger.info(`No ${typeStr} dependencies defined`);
this.logger.info(`Skipping ${typeStr} dependencies`);
}
} else {
this.logger.info(`Skipping ${typeStr} dependencies`);
}
};
}
}
3 changes: 3 additions & 0 deletions src/utils/packageJsonParser/interfaces/IPackageJsonParser.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { IPredicate } from '../../predicateBuilder/predicateBuilder';

export enum DependencyType {
PROD = `production`,
DEV = `development`,
Expand All @@ -24,6 +26,7 @@ export interface IPackageJsonParseOptions {
peer: boolean;
global: boolean;
};
predicate: IPredicate;
}

export interface IPackageJsonData {
Expand Down
57 changes: 57 additions & 0 deletions src/utils/predicateBuilder/predicateBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// @ts-ignore
import regexParserFn from 'regex-parser';

type RegexParser = (str: string) => RegExp;
const regexParser: RegexParser = regexParserFn;

const spaceSplitter = (str: string): string[] => str.split(` `);

const trimmer = (str: string): string => str.trim();

const parsePredicate = (str: string | undefined): IPredicate[] => {
if (!str) {
return [];
}
return str.split(`,`).flatMap(spaceSplitter).map(trimmer).filter(Boolean).map(regexParser).map(compose);
};

const compose = (regex: RegExp): IPredicate => (predicate: string): boolean => regex.test(predicate);

const truthy: IPredicate = (): boolean => true;

const not = (predicate: IPredicate): IPredicate => (str: string): boolean => !predicate(str);

const or = (predicate1: IPredicate, predicate2: IPredicate): IPredicate => (str: string): boolean =>
predicate1(str) || predicate2(str);

const orReducer = (prev: IPredicate, current: IPredicate): IPredicate => {
return or(prev, current);
};

const and = (predicate1: IPredicate, predicate2: IPredicate): IPredicate => (str: string): boolean =>
predicate1(str) && predicate2(str);

const andReducer = (prev: IPredicate, current: IPredicate): IPredicate => {
return and(prev, current);
};

export interface IPredicateBuilderOptions {
include: string | undefined;
exclude: string | undefined;
}

export type IPredicate = (str: string) => boolean;

export const buildPredicate = (options: IPredicateBuilderOptions): IPredicate => {
const include = parsePredicate(options.include);
if (include.length === 0) {
include.push(truthy);
}
const includePredicate = include.reduce(orReducer);
const exclude = parsePredicate(options.exclude).map(not);
if (exclude.length === 0) {
exclude.push(truthy);
}
const excludePredicate = exclude.reduce(andReducer);
return and(includePredicate, excludePredicate);
};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5946,6 +5946,11 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"

regex-parser@^2.2.10:
version "2.2.10"
resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.10.tgz#9e66a8f73d89a107616e63b39d4deddfee912b37"
integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA==

regexpp@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
Expand Down

0 comments on commit f41ff63

Please sign in to comment.