Skip to content

Commit

Permalink
feat(prh): コード全体を見返してAPIを整理した
Browse files Browse the repository at this point in the history
  • Loading branch information
vvakame committed May 6, 2017
1 parent f5d9b9d commit ad0b89e
Show file tree
Hide file tree
Showing 18 changed files with 330 additions and 293 deletions.
50 changes: 35 additions & 15 deletions lib/changeset/changeset.ts
@@ -1,7 +1,21 @@
import Diff from "./diff";
import { Diff } from "./diff";

export interface ChangeSetParams {
filePath?: string;
content: string;
diffs: Diff[];
}

export class ChangeSet {
filePath?: string;
content: string;
diffs: Diff[];

constructor(params: ChangeSetParams) {
this.filePath = params.filePath;
this.content = params.content;
this.diffs = params.diffs;

export default class ChangeSet {
constructor(public diffs: Diff[] = []) {
this._prepare();
}

Expand All @@ -10,11 +24,9 @@ export default class ChangeSet {
this.diffs = this.diffs.sort((a, b) => a.index - b.index);
}

concat(other: ChangeSet): ChangeSet {
this._prepare();
other._prepare();

concat(other: ChangeSet): this {
this.diffs = this.diffs.concat(other.diffs);
this._prepare();
return this;
}

Expand All @@ -26,8 +38,8 @@ export default class ChangeSet {
if (data.expected == null) {
return;
}
let result = data.expected.replace(/\$([0-9]{1,2})/g, (match: string, g1: string) => {
let index = parseInt(g1, 10);
const result = data.expected.replace(/\$([0-9]{1,2})/g, (match: string, g1: string) => {
const index = parseInt(g1, 10);
if (index === 0 || (data.matches.length - 1) < index) {
return match;
}
Expand All @@ -44,13 +56,17 @@ export default class ChangeSet {
this._prepare();
subtrahend._prepare();

let result: ChangeSet = new ChangeSet(this.diffs.map(v => v));
const result: ChangeSet = new ChangeSet({
filePath: this.filePath,
content: this.content,
diffs: this.diffs.map(v => v),
});
let m = 0;
let s = 0;

while (true) {
let minuendDiff = result.diffs[m];
let subtrahendDiff = subtrahend.diffs[s];
const minuendDiff = result.diffs[m];
const subtrahendDiff = subtrahend.diffs[s];

if (!minuendDiff || !subtrahendDiff) {
break;
Expand All @@ -73,13 +89,17 @@ export default class ChangeSet {
this._prepare();
audit._prepare();

let result: ChangeSet = new ChangeSet();
const result: ChangeSet = new ChangeSet({
filePath: this.filePath,
content: this.content,
diffs: [],
});
let a = 0;
let b = 0;

while (true) {
let baseDiff = this.diffs[a];
let auditDiff = audit.diffs[b];
const baseDiff = this.diffs[a];
const auditDiff = audit.diffs[b];
if (!baseDiff || !auditDiff) {
break;
}
Expand Down
26 changes: 17 additions & 9 deletions lib/changeset/diff.ts
@@ -1,18 +1,26 @@
import Rule from "../rule";
import { Rule } from "../rule";

export default class Diff {
export interface DiffParams {
pattern: RegExp;
expected: string | null;
expected?: string; // replaceが必要ないパターンの時渡されない場合がある
index: number;
matches: string[];
rule?: Rule;
}

export class Diff {
pattern: RegExp;
expected?: string;
index: number;
matches: string[];
rule?: Rule;

constructor(pattern: RegExp, expected: string | null, index: number, matches: string[], rule?: Rule) {
this.pattern = pattern;
this.expected = expected;
this.index = index;
this.matches = matches;
this.rule = rule;
constructor(params: DiffParams) {
this.pattern = params.pattern;
this.expected = params.expected;
this.index = params.index;
this.matches = params.matches;
this.rule = params.rule;
}

get tailIndex() {
Expand Down
16 changes: 7 additions & 9 deletions lib/changeset/index.ts
@@ -1,14 +1,12 @@
import * as r from "../utils/regexp";
import Diff from "./diff";
import ChangeSet from "./changeset";
import { collectAll } from "../utils/regexp";
import { Diff } from "./diff";
import { ChangeSet } from "./changeset";

export { ChangeSet, Diff };

export function makeChangeSet(content: string, pattern: RegExp, expected: string | null): ChangeSet {
export function makeChangeSet(filePath: string, content: string, pattern: RegExp, expected?: string): ChangeSet {
pattern.lastIndex = 0;
let resultList = r.collectAll(pattern, content);
let diffs = resultList.map(result => {
return new Diff(pattern, expected, result.index, <string[]>Array.prototype.slice.call(result));
});
return new ChangeSet(diffs);
const resultList = collectAll(pattern, content);
const diffs = resultList.map(matches => new Diff({ pattern, expected, index: matches.index, matches }));
return new ChangeSet({ filePath, content, diffs });
}
24 changes: 12 additions & 12 deletions lib/cli.ts
@@ -1,10 +1,10 @@
import * as path from "path";
import * as fs from "fs";
import * as yaml from "js-yaml";
import * as lib from "./";
import { fromYAMLFilePath } from "./";

import * as commandpost from "commandpost";
let pkg = require("../package.json");
const pkg = require("../package.json");

interface RootOpts {
json: boolean;
Expand All @@ -17,33 +17,33 @@ interface RootArgs {
files: string[];
}

let root = commandpost
const root = commandpost
.create<RootOpts, RootArgs>("prh <files...>")
.version(pkg.version, "-v, --version")
.option("--json", "rule set to json")
.option("--yaml", "rule set to parsed yaml")
.option("--rules <path>", "path to rule yaml file")
.option("-r, --replace", "replace input files")
.action((opts, args) => {
let paths = [getConfigFileName(process.cwd(), "prh.yml") || __dirname + "/../rules/media/WEB+DB_PRESS.yml"];
let paths = [getConfigFileName(process.cwd(), "prh.yml") || path.resolve(__dirname, "../rules/media/WEB+DB_PRESS.yml")];
if (opts.rules && opts.rules[0]) {
paths = opts.rules;
}
let config = lib.fromYAMLFilePath(paths[0]);
const engine = fromYAMLFilePath(paths[0]);
paths.splice(1).forEach(path => {
let c = lib.fromYAMLFilePath(path);
config.merge(c);
const e = fromYAMLFilePath(path);
engine.merge(e);
});

if (opts.json) {
console.log(JSON.stringify(config, null, 2));
console.log(JSON.stringify(engine, null, 2));
return;
} else if (opts.yaml) {
console.log(yaml.dump(JSON.parse(JSON.stringify(config, null, 2))));
console.log(yaml.dump(JSON.parse(JSON.stringify(engine, null, 2))));
return;
}
args.files.forEach(filePath => {
let result = config.replaceByRule(filePath);
const result = engine.replaceByRule(filePath);
if (opts.replace) {
fs.writeFileSync(filePath, result);
} else {
Expand All @@ -56,7 +56,7 @@ root
.subCommand<{}, {}>("init")
.description("generate prh.yml")
.action((_opts, _args) => {
fs.createReadStream(__dirname + "/../misc/prh.yml").pipe(fs.createWriteStream("prh.yml"));
fs.createReadStream(path.resolve(__dirname, "../misc/prh.yml")).pipe(fs.createWriteStream("prh.yml"));
console.log("create prh.yml");
console.log("see prh/rules collection https://github.com/prh/rules");
});
Expand All @@ -77,7 +77,7 @@ function errorHandler(err: any) {
}

export function getConfigFileName(baseDir: string, configFileName: string): string | null {
let configFilePath = path.resolve(baseDir, configFileName);
const configFilePath = path.resolve(baseDir, configFileName);
if (fs.existsSync(configFilePath)) {
return configFilePath;
}
Expand Down
59 changes: 31 additions & 28 deletions lib/engine.ts
@@ -1,13 +1,13 @@
import * as fs from "fs";

import * as r from "./utils/regexp";
import { equals } from "./utils/regexp";

import * as raw from "./raw";
import Target from "./target";
import Rule from "./rule";
import * as changeSet from "./changeset";
import { Target } from "./target";
import { Rule } from "./rule";
import { makeChangeSet, ChangeSet } from "./changeset";

export default class Engine {
export class Engine {
version: number;
targets: Target[];
rules: Rule[];
Expand All @@ -29,66 +29,69 @@ export default class Engine {
throw new Error("version mismatch!");
}
other.targets.forEach(otherTarget => {
let exists = this.targets.filter(target => r.equals(target.file, otherTarget.file)).length !== 0;
const exists = this.targets.filter(target => equals(target.file, otherTarget.file)).length !== 0;
if (!exists) {
this.targets.push(otherTarget);
}
});
// NOTE https://github.com/vvakame/prh/issues/18#issuecomment-222524140
let reqRules = other.rules.filter(otherRule => {
const reqRules = other.rules.filter(otherRule => {
return this.rules.filter(rule => rule.expected === otherRule.expected).length === 0;
});
this.rules = this.rules.concat(reqRules);
}

makeChangeSet(filePath: string, contentArg?: string): changeSet.ChangeSet {
makeChangeSet(filePath: string, contentArg?: string): ChangeSet {
const content: string = contentArg != null ? contentArg : fs.readFileSync(filePath, { encoding: "utf8" });
let changeSets = new changeSet.ChangeSet();
this.rules.forEach(rule => {
let set = rule.applyRule(content);
changeSets = changeSets.concat(set);
});
const diffs = this.rules.map(rule => rule.applyRule(content)).reduce((p, c) => p.concat(c), []);
let changeSet = new ChangeSet({ filePath, content, diffs });

let includes = new changeSet.ChangeSet();
let excludes = new changeSet.ChangeSet();
let includesExists = false;
let excludesExists = false;
let includes: ChangeSet | null = null;
let excludes: ChangeSet | null = null;
this.targets.forEach(target => {
target.reset();
if (!target.file.test(filePath)) {
return;
}
if (target.includes.length !== 0) {
// .ts の // の後や /* */ の内部だけ対象にしたい場合のための機能
includesExists = true;
target.includes.forEach(include => {
includes = includes.concat(changeSet.makeChangeSet(content, include.pattern, null));
const intersect = makeChangeSet(filePath, content, include.pattern);
if (includes) {
includes = includes.concat(intersect);
} else {
includes = intersect;
}
});
}
if (target.excludes.length !== 0) {
// .re の #@ の後を対象にしたくない場合のための機能
excludesExists = true;
target.excludes.forEach(exclude => {
excludes = excludes.concat(changeSet.makeChangeSet(content, exclude.pattern, null));
const subsract = makeChangeSet(filePath, content, exclude.pattern);
if (excludes) {
excludes = excludes.concat(subsract);
} else {
excludes = subsract;
}
});
}
});

if (includesExists) {
changeSets = changeSets.intersect(includes);
if (includes) {
changeSet = changeSet.intersect(includes);
}
if (excludesExists) {
changeSets = changeSets.subtract(excludes);
if (excludes) {
changeSet = changeSet.subtract(excludes);
}

return changeSets;
return changeSet;
}

replaceByRule(filePath: string, content?: string) {
if (content == null) {
content = fs.readFileSync(filePath, { encoding: "utf8" });
}
let changeSets = this.makeChangeSet(filePath, content);
return changeSets.applyChangeSets(content);
const changeSet = this.makeChangeSet(filePath, content);
return changeSet.applyChangeSets(content);
}
}
16 changes: 8 additions & 8 deletions lib/index.ts
Expand Up @@ -3,30 +3,30 @@ import * as path from "path";
import * as yaml from "js-yaml";

import * as raw from "./raw";
import Engine from "./engine";
import { Engine } from "./engine";
import { ChangeSet, Diff } from "./changeset/";

export { Engine, ChangeSet, Diff };

export function fromYAMLFilePath(configPath: string): Engine {
let content = fs.readFileSync(configPath, { encoding: "utf8" });
const content = fs.readFileSync(configPath, { encoding: "utf8" });
return fromYAML(configPath, content);
}

export function fromYAML(configPath: string, yamlContent: string): Engine {
let rawConfig = yaml.load(yamlContent);
const rawConfig = yaml.load(yamlContent);
return fromRowConfig(configPath, rawConfig);
}

export function fromRowConfig(configPath: string, rawConfig: raw.Config): Engine {
let engine = new Engine(rawConfig);
const engine = new Engine(rawConfig);

if (rawConfig.imports) {
let tmp = rawConfig.imports;
let imports = typeof tmp === "string" ? [tmp] : tmp;
const tmp = rawConfig.imports;
const imports = typeof tmp === "string" ? [tmp] : tmp;
imports.forEach(im => {
let importedConfigPath = path.resolve(path.dirname(configPath), im);
let newEngine = fromYAMLFilePath(importedConfigPath);
const importedConfigPath = path.resolve(path.dirname(configPath), im);
const newEngine = fromYAMLFilePath(importedConfigPath);
engine.merge(newEngine);
});
}
Expand Down
4 changes: 2 additions & 2 deletions lib/options.ts
@@ -1,7 +1,7 @@
import * as raw from "./raw";
import Rule from "./rule";
import { Rule } from "./rule";

export default class Options {
export class Options {
wordBoundary: boolean;

constructor(_rule: Rule, src?: raw.Options) {
Expand Down

0 comments on commit ad0b89e

Please sign in to comment.