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 f41ff63 commit 1edbe34
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 28 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@
"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
8 changes: 7 additions & 1 deletion src/utils/packageJsonParser/impl/packageJsonParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import { inject, injectable } from 'inversify';
import { FS, TYPES } from '../../../container/nodeModulesContainer';
import { ILoggerFactory } from '../../logger';
import { ILogger } from '../../logger/interfaces/ILogger';
import { Dependency, DependencyType, IPackageJsonData, IPackageJsonParseOptions, IPackageJsonParser } from '..';
import {
Dependency,
DependencyType,
IPackageJsonData,
IPackageJsonParseOptions,
IPackageJsonParser,
} from '../interfaces/IPackageJsonParser';
import * as path from 'path';
import { Manifest } from 'pacote';
import { IPredicate } from '../../predicateBuilder/predicateBuilder';
Expand Down
43 changes: 22 additions & 21 deletions src/utils/predicateBuilder/predicateBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// @ts-ignore
import regexParserFn from 'regex-parser';
const regexMatcher = /\/(.+)\/([a-z]*)/i;

type RegexParser = (str: string) => RegExp;
const regexParser: RegexParser = regexParserFn;
const regexParser = (input: string): IPredicate => {
const match = regexMatcher.exec(input);
if (!match) {
return (predicate: string): boolean => predicate === input;
}
const regex = new RegExp(match[1], match[2]);
return (predicate: string): boolean => {
regex.lastIndex = 0;
return regex.test(predicate);
};
};

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

Expand All @@ -12,11 +20,9 @@ const parsePredicate = (str: string | undefined): IPredicate[] => {
if (!str) {
return [];
}
return str.split(`,`).flatMap(spaceSplitter).map(trimmer).filter(Boolean).map(regexParser).map(compose);
return str.split(`,`).flatMap(spaceSplitter).map(trimmer).filter(Boolean).map(regexParser);
};

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);
Expand All @@ -35,23 +41,18 @@ 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);
export const buildPredicate = (include: string | undefined, exclude: string | undefined): IPredicate => {
const includeArr = parsePredicate(include);
if (includeArr.length === 0) {
includeArr.push(truthy);
}
const includePredicate = include.reduce(orReducer);
const exclude = parsePredicate(options.exclude).map(not);
if (exclude.length === 0) {
exclude.push(truthy);
const includePredicate = includeArr.reduce(orReducer);
const excludeArr = parsePredicate(exclude).map(not);
if (excludeArr.length === 0) {
excludeArr.push(truthy);
}
const excludePredicate = exclude.reduce(andReducer);
const excludePredicate = excludeArr.reduce(andReducer);
return and(includePredicate, excludePredicate);
};
86 changes: 86 additions & 0 deletions test/src/utils/predicateBuilder/predicateBuilder.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { buildPredicate } from '../../../../src/utils/predicateBuilder/predicateBuilder';

describe(`predicate builder`, () => {
it(`should return truthy predicate from undefined include and exclude`, () => {
const predicate = buildPredicate(undefined, undefined);
expect(predicate(`dummy`)).toBe(true);
});

it(`should return truthy predicate from empty include and exclude`, () => {
const predicate = buildPredicate(``, ``);
expect(predicate(`dummy`)).toBe(true);
});

it(`should return truthy predicate from empty (after trim) include and exclude`, () => {
const predicate = buildPredicate(` `, ` `);
expect(predicate(`dummy`)).toBe(true);
});

it(`should return falsy predicate if include equals exclude`, () => {
const predicate = buildPredicate(`a`, `a`);
expect(predicate(`a`)).toBe(false);
expect(predicate(`b`)).toBe(false);
});

it(`should predicate based on include only`, () => {
const predicate = buildPredicate(`a b c, d`, undefined);
expect(predicate(`a`)).toBe(true);
expect(predicate(`b`)).toBe(true);
expect(predicate(`c`)).toBe(true);
expect(predicate(`d`)).toBe(true);
expect(predicate(`dummy`)).toBe(false);
expect(predicate(`ab`)).toBe(false);
});

it(`should predicate based on exclude only`, () => {
const predicate = buildPredicate(undefined, `a b c, d`);
expect(predicate(`a`)).toBe(false);
expect(predicate(`b`)).toBe(false);
expect(predicate(`c`)).toBe(false);
expect(predicate(`d`)).toBe(false);
expect(predicate(`dummy`)).toBe(true);
expect(predicate(`ab`)).toBe(true);
});

it(`should predicate based on include and exclude`, () => {
const predicate = buildPredicate(`a, b`, `c, d`);
expect(predicate(`a`)).toBe(true);
expect(predicate(`b`)).toBe(true);
expect(predicate(`c`)).toBe(false);
expect(predicate(`d`)).toBe(false);
expect(predicate(`dummy`)).toBe(false);
expect(predicate(`ab`)).toBe(false);
});

it(`should predicate based on include and exclude intersection`, () => {
const predicate = buildPredicate(`/a/`, `a`);
expect(predicate(`a`)).toBe(false);
expect(predicate(`ab`)).toBe(true);
expect(predicate(`c`)).toBe(false);
});

it(`should predicate based on include and exclude intersection 2`, () => {
const predicate = buildPredicate(`a`, `/a/`);
expect(predicate(`a`)).toBe(false);
expect(predicate(`ab`)).toBe(false);
expect(predicate(`c`)).toBe(false);
});

it(`should predicate based on regex flags`, () => {
const predicate = buildPredicate(`/a/`, undefined);
expect(predicate(`a`)).toBe(true);
expect(predicate(`A`)).toBe(false);
});

it(`should predicate based on regex flags 2`, () => {
const predicate = buildPredicate(`/a/i`, undefined);
expect(predicate(`a`)).toBe(true);
expect(predicate(`A`)).toBe(true);
});

it(`should predicate based on regex global flag`, () => {
const predicate = buildPredicate(`/a/g`, undefined);
expect(predicate(`a`)).toBe(true);
expect(predicate(`a`)).toBe(true);
});
});
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5946,11 +5946,6 @@ 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 1edbe34

Please sign in to comment.