Skip to content

Commit

Permalink
feat(core): adds cwd option for IScopeOptions; improves type definiti…
Browse files Browse the repository at this point in the history
…ons for package, cli, and core
  • Loading branch information
rafamel committed Apr 28, 2019
1 parent 4bf1fba commit 63766bc
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 45 deletions.
45 changes: 30 additions & 15 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,46 @@ const core = {
directory: options.directory || undefined
});
}),
root: cache(async function(): Promise<IPaths | null> {
load: cache(async function(): Promise<ILoaded> {
return load(await core.paths());
}),
cwd: cache(async function(): Promise<string> {
const cwd = await core.get('cwd');
const paths = await core.paths();
if (!cwd) return paths.directory;

// as cwd is a IScopeOptions property -it can't be set on cli-
// if it is set and it's not absolute, it must be relative
// to a kpo scripts file -if on package.json it was already set as absolute
if (!path.isAbsolute(cwd)) {
const dir = paths.kpo ? path.parse(paths.kpo).dir : paths.directory;
return path.join(dir, cwd);
}

return cwd;
}),
root: cache(async function(): Promise<IPaths | null> {
const cwd = await core.cwd();

return getRootPaths({
self: paths.directory,
cwd,
root: await core.get('root')
});
}),
children: cache(async function(): Promise<IChild[]> {
const paths = await core.paths();
const cwd = await core.cwd();
const children = await core.get('children');

return getChildren(paths.directory, children);
}),
load: cache(async function(): Promise<ILoaded> {
return load(await core.paths());
return getChildren(
{ cwd, pkg: paths.pkg ? path.parse(paths.pkg).dir : cwd },
children
);
}),
bin: cache(async function(): Promise<string[]> {
const paths = await core.paths();
const cwd = await core.cwd();
const root = await core.root();
return root
? getBin(paths.directory, root.directory)
: getBin(paths.directory);
return root ? getBin(cwd, root.directory) : getBin(cwd);
}),
tasks: cache(async function(): Promise<ITasks> {
const { kpo, pkg } = await core.load();
Expand All @@ -91,25 +108,23 @@ const core = {
fork: boolean,
opts: IExecOptions = {}
): Promise<void> {
const paths = await core.paths();
const cwd = opts.cwd
? path.isAbsolute(opts.cwd)
? opts.cwd
: path.join(paths.directory, opts.cwd)
: paths.directory;
: path.join(await core.cwd(), opts.cwd)
: await core.cwd();
const bin = opts.cwd ? await getBin(cwd) : await core.bin();
const env = opts.env
? Object.assign({}, await core.get('env'), opts.env)
: await core.get('env');
return exec(command, args, fork, cwd, bin, env);
},
async setScope(names: string[]): Promise<void> {
const paths = await core.paths();
const root = await core.root();

const { next, scope } = await setScope(
names,
{ self: paths.directory, root: root ? root.directory : undefined },
{ root: root ? root.directory : undefined },
await core.children()
);
if (scope) {
Expand Down
11 changes: 7 additions & 4 deletions src/core/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import yaml from 'js-yaml';
import { rejects } from 'errorish';
import { open } from '~/utils/errors';
import { ILoaded, IPaths } from './types';
import { IOfType, TCoreOptions } from '~/types';
import { IOfType, IPackageOptions } from '~/types';
import options from './options';

export default async function load(paths: IPaths): Promise<ILoaded> {
// pkg must be loaded first to set options first, if present at key `kpo`
const pkg = paths.pkg
? await fs
.readJSON(paths.pkg)
.then(processPkg)
.then((pkg) => processPkg(paths.pkg as string, pkg))
.catch(rejects)
: null;

Expand Down Expand Up @@ -52,13 +52,16 @@ export function processStatic(kpo: IOfType<any>): IOfType<any> | null {
return kpo.scripts || null;
}

export function processPkg(pkg: IOfType<any>): IOfType<any> {
export function processPkg(file: string, pkg: IOfType<any>): IOfType<any> {
if (!pkg || !pkg.kpo) return pkg;

const opts: TCoreOptions = Object.assign({}, pkg.kpo);
const opts: IPackageOptions = Object.assign({}, pkg.kpo);
// file was already read when getting paths;
// it's also not a IScopeOptions field
delete opts.file;
if (opts.cwd && !path.isAbsolute(opts.cwd)) {
opts.cwd = path.join(path.parse(file).dir, opts.cwd);
}

options.setScope(opts);
return pkg;
Expand Down
9 changes: 5 additions & 4 deletions src/core/options.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IBaseOptions, IScopeOptions, TCoreOptions, IOfType } from '~/types';
import { ICliOptions, IScopeOptions, TCoreOptions, IOfType } from '~/types';
import { DEFAULT_LOG_LEVEL } from '~/constants';
import { setLevel } from '~/utils/logger';
import hash from 'object-hash';
Expand All @@ -10,8 +10,8 @@ export const state = {
env: {},
silent: false,
log: DEFAULT_LOG_LEVEL
} as IBaseOptions,
cli: {} as IBaseOptions,
} as TCoreOptions,
cli: {} as ICliOptions,
scope: {} as IScopeOptions
};

Expand All @@ -24,7 +24,7 @@ export default {
get id(): string {
return id;
},
setCli(opts: IBaseOptions): void {
setCli(opts: ICliOptions): void {
Object.assign(state.cli, stripUndefined(opts));
merge();
},
Expand All @@ -46,6 +46,7 @@ function merge(): void {

// ensure cli own properties are of cli
options.file = state.cli.file || state.base.file;
options.directory = state.cli.directory || state.base.directory;

// Set logging level
if (options.log) setLevel(options.log);
Expand Down
8 changes: 4 additions & 4 deletions src/core/paths/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ export async function getSelfPaths(opts: {
* Will recurse up when `directories.root` is undefined; otherwise it will expect the project directory to be exactly `directories.root`.
*/
export async function getRootPaths(directories: {
self: string;
cwd: string;
root?: string | null;
}): Promise<IPaths | null> {
const { self, root } = directories;
const { cwd, root } = directories;
if (root === null) return null;

const directory = root
? path.isAbsolute(root)
? root
: path.join(self, root)
: path.join(self, '../');
: path.join(cwd, root)
: path.join(cwd, '../');

try {
return await getPaths({ directory }, Boolean(root));
Expand Down
12 changes: 6 additions & 6 deletions src/core/scope/children/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IChild } from '../../types';
import { TChildrenDefinition } from '~/types';

export default async function getChildren(
directory: string,
directories: { cwd: string; pkg: string },
definition?: TChildrenDefinition
): Promise<IChild[]> {
logger.debug('obtaining children');
Expand All @@ -18,19 +18,19 @@ export default async function getChildren(
logger.debug('children found in options');

if (Array.isArray(definition)) {
return getChildrenFromGlobs(definition, directory);
return getChildrenFromGlobs(definition, directories.cwd);
}
return getChildrenFromMap(definition, directory);
return getChildrenFromMap(definition, directories.cwd);
}

const lerna = (await exists(path.join(directory, 'lerna.json')))
? await fs.readJSON(path.join(directory, 'lerna.json')).catch(rejects)
const lerna = (await exists(path.join(directories.pkg, 'lerna.json')))
? await fs.readJSON(path.join(directories.pkg, 'lerna.json')).catch(rejects)
: null;

if (lerna) {
logger.debug('lerna file found');
if (lerna.packages) {
return getChildrenFromGlobs(lerna.packages, directory);
return getChildrenFromGlobs(lerna.packages, directories.pkg);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/scope/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IScope, IChild } from '../types';

export default async function setScope(
scopes: string[],
directories: { self: string; root?: string },
directories: { root?: string },
children: IChild[]
): Promise<{ next: string[]; scope?: IScope }> {
if (!scopes.length) return { next: [] };
Expand Down
37 changes: 26 additions & 11 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export type TScript =
| TScriptFn
| IScriptsArray;

// TODO use for all
/**
* Represents a `TScript` as a function
*/
Expand All @@ -68,12 +67,6 @@ export interface IScripts {
}

export interface IOptions {
/**
* Project directory.
* Used for relative paths resolution and as default `cwd` on command execution.
* By default, it will be the directory in which a sibling or parent `package.json` is found for the *kpo* scripts file, or the directory of the *kpo* file itself otherwise.
*/
directory?: string | null;
/**
* Environment variables.
*/
Expand All @@ -100,22 +93,44 @@ export interface IScopeOptions extends IOptions {
* Paths . They can be defined as an array of globs, or otherwise an exclusive map of scope names and directories. See `TChildrenDefinition`. By default, it will be inferred if your project directory contains a `lerna.json` file from its `packages` key globs.
*/
children?: TChildrenDefinition;
// TODO implement cwd (instead of directory)
// account for relative paths
/**
* Used for relative paths resolution and as default `cwd` on command execution. It is also the directory scopes are resolved from.
* By default, it will be the directory in which a sibling or parent `package.json` is found for the *kpo* scripts file, or the directory of the *kpo* file itself otherwise, unless a explicit `directory` is passed on the cli -see `ICliOptions`.
* If it is a relative path itself, it will be resolved:
* - relative to the process `cwd` if passed on the cli.
* - relative to the `package.json` if set as an option there.
* - relative to the *kpo* scripts file if set there.
*/
cwd?: string;
}

/**
* Options taken by the CLI.
* Options that can live in the `kpo` key of a `package.json`.
*/
export interface IBaseOptions extends IOptions {
export interface IPackageOptions extends IScopeOptions {
/**
* The location of the *kpo* scripts file for the project.
*/
file?: string | null;
}

/**
* Options that can live in the `kpo` key of a `package.json`.
* Options taken by the CLI.
*/
export type TCoreOptions = IBaseOptions & IScopeOptions;
export interface ICliOptions extends IOptions {
/**
* The location of the *kpo* scripts file for the project.
*/
file?: string | null;
/**
* Project directory, used to find the *kpo* scripts `file` or `package.json`, and as a default `cwd`.
*/
directory?: string | null;
}

export type TCoreOptions = ICliOptions & IPackageOptions;

/**
* A project children scopes, defined either:
Expand Down

0 comments on commit 63766bc

Please sign in to comment.