Skip to content

Commit

Permalink
feat!: Lookup configPath in configFiles (#128)
Browse files Browse the repository at this point in the history
  • Loading branch information
phated committed Mar 16, 2024
1 parent 466e17b commit 5301335
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 7 deletions.
22 changes: 17 additions & 5 deletions README.md
Expand Up @@ -165,6 +165,8 @@ Default: `null`

An object of configuration files to find. Each property is keyed by the default basename of the file being found, and the value is an array of [path arguments](#path-arguments) of which the order indicates priority to find.

See [Config Files](#config-files) for the config file specification.

**Note:** This option is useful if, for example, you want to support an `.apprc` file in addition to an `appfile.js`. If you only need a single configuration file, you probably don't need this. In addition to letting you find multiple files, this option allows more fine-grained control over how configuration files are located.

Type: `Object`
Expand Down Expand Up @@ -337,11 +339,7 @@ const onExecute = function (env, argv) {
};
const onPrepare = function (env) {
const config = env.config['.hacker'];
if (config.hackerfile) {
env.configPath = path.resolve(config.hackerfile);
env.configBase = path.dirname(env.configPath);
}
Hacker.execute(env, onExecute);
Hacker.execute(env, config.forcedFlags, onExecute);
};
Hacker.prepare({}, onPrepare);
```
Expand Down Expand Up @@ -457,6 +455,7 @@ A function called after your environment is prepared. A good place to modify the
- `modulePath`: the full path to the local module your project relies on (if found)
- `modulePackage`: the contents of the local module's package.json (if found)
- `configFiles`: an object of filepaths for each found config file (filepath values will be null if not found)
- `config`: an object with keys matching `configFiles` but with the loaded config object

### execute(env, [forcedFlags], callback(env, argv))

Expand Down Expand Up @@ -492,6 +491,7 @@ A function called after your application is executed. When invoked, `this` will
- `modulePath`: the full path to the local module your project relies on (if found)
- `modulePackage`: the contents of the local module's package.json (if found)
- `configFiles`: an object of filepaths for each found config file (filepath values will be null if not found)
- `config`: an object with keys matching `configFiles` but with the loaded config object

### events

Expand Down Expand Up @@ -582,6 +582,18 @@ Hacker.on('respawn', function (flags, child) {
Event will be triggered for this command:
`hacker --harmony commmand`

## Config files

Liftoff supports a small definition of config files, but all details provided by users will be available in `env.config`.

### `extends`

All `extends` properties will be traversed and become the basis for the resulting config object. Any path provided for `extends` will be loaded with node's `require`, so all extensions and loaders supported on the Liftoff instance will be available to them.

### Field matching the `configName`

Users can override the `configPath` via their config files by specifying a field with the same name as the primary `configName`. For example, the `hackerfile` property in a `configFile` will resolve the `configPath` and `configBase` against the path.

## Examples

Check out how [gulp][gulp-cli-index] uses Liftoff.
Expand Down
20 changes: 18 additions & 2 deletions index.js
Expand Up @@ -50,6 +50,8 @@ Liftoff.prototype.buildEnvironment = function (opts) {

// make a copy of search paths that can be mutated for this run
var searchPaths = this.searchPaths.slice();
// store the instance configName to use in closures without access to `this`
var configName = this.configName;

// calculate current cwd
var cwd = findCwd(opts);
Expand Down Expand Up @@ -113,6 +115,13 @@ Liftoff.prototype.buildEnvironment = function (opts) {
'Encountered error when loading config file: ' + configFilePath
);
}

// resolve something like `{ gulpfile: "./abc.xyz" }` to the absolute path
// based on the path of the configFile
if (Object.prototype.hasOwnProperty.call(configFile, configName)) {
configFile[configName] = path.resolve(path.dirname(configFilePath), configFile[configName]);
}

visited[configFilePath] = true;
if (configFile && configFile.extends) {
var nextCwd = path.dirname(configFilePath);
Expand Down Expand Up @@ -146,6 +155,13 @@ Liftoff.prototype.buildEnvironment = function (opts) {
return loadConfig(cwd, startingLocation, defaultConfig);
});

var configPathOverride = arrayFind(Object.keys(config), function (key) {
var cfg = config[key];
if (Object.prototype.hasOwnProperty.call(cfg, configName)) {
return cfg[configName];
}
});

// if cwd was provided explicitly, only use it for searching config
if (opts.cwd) {
searchPaths = [cwd];
Expand All @@ -156,15 +172,15 @@ Liftoff.prototype.buildEnvironment = function (opts) {

// calculate the regex to use for finding the config file
var configNameSearch = buildConfigName({
configName: this.configName,
configName: configName,
extensions: Object.keys(this.extensions),
});

// calculate configPath
var configPath = findConfig({
configNameSearch: configNameSearch,
searchPaths: searchPaths,
configPath: opts.configPath,
configPath: opts.configPath || configPathOverride,
});

// if we have a config path, save the directory it resides in.
Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/configfiles/override-config-path-absolute.js
@@ -0,0 +1,5 @@
var path = require('path');

module.exports = {
myappfile: path.join(__dirname, "../override-the-config-path.js"),
};
3 changes: 3 additions & 0 deletions test/fixtures/configfiles/override-config-path-relative.json
@@ -0,0 +1,3 @@
{
"myappfile": "../override-the-config-path.js"
}
Empty file.
30 changes: 30 additions & 0 deletions test/index.js
Expand Up @@ -571,6 +571,36 @@ describe('Liftoff', function () {
);
});

it('overrides the configPath if the configName key exists in the config', function (done) {
var app = new Liftoff({
name: 'myapp',
configFiles: {
'override-config-path-absolute': [
{ path: 'test/fixtures/configfiles', extensions: ['.js'] }
],
},
});
app.prepare({}, function (env) {
expect(env.configPath).toMatch(/override-the-config-path\.js$/);
done();
});
});

it('resolves relative configPath if the configName key exists in the config', function (done) {
var app = new Liftoff({
name: 'myapp',
configFiles: {
'override-config-path-relative': [
{ path: 'test/fixtures/configfiles', extensions: ['.json'] }
],
},
});
app.prepare({}, function (env) {
expect(env.configPath).toMatch(/override-the-config-path\.js$/);
done();
});
});

it('should use dirname of configPath if no cwd is specified', function (done) {
var app = new Liftoff({
name: 'myapp',
Expand Down

0 comments on commit 5301335

Please sign in to comment.