Skip to content

Commit

Permalink
feat(rule): add support for interpolation in targets
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieMason committed Jul 7, 2019
1 parent de2ddcb commit b486d7f
Show file tree
Hide file tree
Showing 6 changed files with 557 additions and 451 deletions.
6 changes: 0 additions & 6 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,5 @@ export const DEFAULT_OPTIONS = {
rulesDir: process.cwd()
};

export const ERROR_FLAT_DIRECTORY = (source: string, target: string) =>
`Moving multiple files "${source}" to a flat directory at "${target}" is not currently supported`;

export const ERROR_MOVED_FILE = (oldPath: string, newPath: string) =>
`${oldPath} has moved to ${newPath}`;

export const ERROR_MULTIPLE_TARGETS = (source: string, target: string) =>
`Unclear where to move "${source}" when target is "${target}"`;
10 changes: 7 additions & 3 deletions src/lib/get-in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ const isWalkable = (value: any) =>
const getChild = (parent: any, child: any): any =>
isWalkable(parent) ? parent[child] : undefined;

export const getIn = (pathToValue: string, owner?: any, defaultValue?: any) => {
const deepValue = pathToValue.split('.').reduce(getChild, owner);
return typeof deepValue !== 'undefined' ? deepValue : defaultValue;
export const getIn = (
pathToValue: string | number,
owner?: any,
defaultValue?: any
) => {
const value = `${pathToValue}`.split('.').reduce(getChild, owner);
return value !== undefined ? value : defaultValue;
};
142 changes: 142 additions & 0 deletions src/lib/path-reader.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { resolve } from 'path';
import { getValue, interpolate } from './path-reader';

const PWD = process.cwd();

describe('getValue', () => {
type Query = string;
type ExpectedResult = string;
type Assertion = [Query, ExpectedResult];
type AbsolutePath = string;
type Test = [AbsolutePath, Assertion[]];
const tests: Test[] = [
[
resolve(PWD, './src/lib/module.js'),
[
['...', 'src'],
['..', 'lib'],
['.', 'module.js'],
['ancestors.0', 'lib'],
['ancestors.1', 'src'],
['dirs.0', 'src'],
['dirs.1', 'lib'],
['exts.0', 'js'],
['exts.1', ''],
['base', 'module.js'],
['dir', 'src/lib'],
['ext', 'js'],
['name', 'module'],
['rootDir', PWD],
['invalid', ''],
['unrecognised', '']
]
],
[
resolve(PWD, './src/lib/module.spec.js'),
[
['...', 'src'],
['..', 'lib'],
['.', 'module.spec.js'],
['ancestors.0', 'lib'],
['ancestors.1', 'src'],
['dirs.0', 'src'],
['dirs.1', 'lib'],
['exts.0', 'spec'],
['exts.1', 'js'],
['base', 'module.spec.js'],
['dir', 'src/lib'],
['ext', 'spec.js'],
['name', 'module'],
['rootDir', PWD],
['invalid', ''],
['unrecognised', '']
]
],
[
resolve(PWD, './.babelrc'),
[
['...', ''],
['..', ''],
['.', '.babelrc'],
['ancestors.0', ''],
['ancestors.1', ''],
['dirs.0', ''],
['dirs.1', ''],
['exts.0', 'babelrc'],
['exts.1', ''],
['base', '.babelrc'],
['dir', ''],
['ext', 'babelrc'],
['name', ''],
['rootDir', PWD],
['invalid', ''],
['unrecognised', '']
]
],
[
resolve(PWD, './.eslintrc.js'),
[
['...', ''],
['..', ''],
['.', '.eslintrc.js'],
['ancestors.0', ''],
['ancestors.1', ''],
['dirs.0', ''],
['dirs.1', ''],
['exts.0', 'eslintrc'],
['exts.1', 'js'],
['base', '.eslintrc.js'],
['dir', ''],
['ext', 'eslintrc.js'],
['name', ''],
['rootDir', PWD],
['invalid', ''],
['unrecognised', '']
]
]
];

tests.forEach(([absolutePath, assertions]) => {
describe(`when path is '${absolutePath}'`, () => {
assertions.forEach(([query, expected]) => {
describe(`when query is '${query}'`, () => {
it(`returns '${expected}'`, () => {
expect(getValue(query, absolutePath)).toEqual(expected);
});
});
});
});
});
});

describe('interpolate', () => {
type Template = string;
type ExpectedResult = string;
type Assertion = [Template, ExpectedResult];
type AbsolutePath = string;
type Test = [AbsolutePath, Assertion[]];
const tests: Test[] = [
[
resolve(PWD, './src/lib/module.spec.js'),
[
[
'{rootDir}/test/{ancestors.0}/{name}.js',
resolve(PWD, './test/lib/module.js')
],
['{rootDir}/test/{..}/{name}.js', resolve(PWD, './test/lib/module.js')]
]
]
];

tests.forEach(([absolutePath, assertions]) => {
describe(`when path is '${absolutePath}'`, () => {
assertions.forEach(([template, expected]) => {
describe(`when template is '${template}'`, () => {
it(`returns '${expected}'`, () => {
expect(interpolate(template, absolutePath)).toEqual(expected);
});
});
});
});
});
});
56 changes: 56 additions & 0 deletions src/lib/path-reader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { basename, dirname, relative, sep } from 'path';
import { getIn } from './get-in';

const getAncestors = (absPath: string) =>
getDir(absPath)
.split(sep)
.reverse();
const getAncestorsIndex = (query: string) => query.replace('ancestors.', '');
const getBase = (absPath: string) => basename(absPath);
const getDir = (absPath: string) => relative(process.cwd(), dirname(absPath));
const getDirs = (absPath: string) => getDir(absPath).split(sep);
const getDirsIndex = (query: string) => query.replace('dirs.', '');
const getExt = (absPath: string) =>
basename(absPath).slice(basename(absPath).indexOf('.') + 1);
const getExts = (absPath: string) =>
getExt(absPath)
.split('.')
.filter(Boolean);
const getExtsIndex = (query: string) => query.replace('exts.', '');
const getName = (absPath: string) =>
basename(absPath).slice(0, basename(absPath).indexOf('.'));
const getRootDir = () => process.cwd();

export const getValue = (query: string, absPath: string) => {
if (query === 'rootDir') {
return getRootDir();
}
if (query === 'dir') {
return getDir(absPath);
}
if (query === 'base' || query === '.') {
return getBase(absPath);
}
if (query === 'name') {
return getName(absPath);
}
if (query === 'ext') {
return getExt(absPath);
}
if (query.startsWith('dirs.')) {
return getIn(getDirsIndex(query), getDirs(absPath), '');
}
if (query.startsWith('exts.')) {
return getIn(getExtsIndex(query), getExts(absPath), '');
}
if (query.startsWith('ancestors.')) {
return getIn(getAncestorsIndex(query), getAncestors(absPath), '');
}
if (query.search(/^\.+$/) !== -1) {
return getIn(query.length - 2, getAncestors(absPath), '');
}
return '';
};

export const interpolate = (template: string, absPath: string) =>
template.replace(/{([^,}]+)}/g, (_, query) => getValue(query, absPath));
Loading

0 comments on commit b486d7f

Please sign in to comment.