Skip to content

Commit

Permalink
WIP allow specifying config file location
Browse files Browse the repository at this point in the history
  • Loading branch information
chris48s committed Oct 21, 2024
1 parent 310aac0 commit cb721ae
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 81 deletions.
9 changes: 7 additions & 2 deletions docs/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ v8r uses [CosmiConfig](https://www.npmjs.com/package/cosmiconfig) to search for
- `v8r.config.js`
- `v8r.config.cjs`

v8r only searches for a config file in the current working directory.
By default, v8r searches for a config file in the current working directory.

If you want to load a config file from another location, you can invoke v8r with the `V8R_CONFIG_FILE` environment variable. All patterns and relative paths in the config file will be resolved relative to the current working directory rather than the config file location, even if the config file is loaded from somewhere other than the current working directory.

Example yaml config file:

```yaml title=".v8rrc.yml"
# - One or more filenames or glob patterns describing local file or files to validate
# Patterns are resolved relative to the current working directory.
# - overridden by passing one or more positional arguments
patterns: ['*.json']

Expand Down Expand Up @@ -59,13 +62,14 @@ customCatalog:
description: Custom Schema # A description of the schema (optional)

# A Minimatch glob expression for matching up file names with a schema (required)
# Expressions are resolved relative to the current working directory.
fileMatch: ["*.geojson"]

# A URL or local file path for the schema location (required)
# Unlike the SchemaStore.org format, which has a `url` key,
# custom catalogs defined in v8r config files have a `location` key
# which can refer to either a URL or local file.
# Relative paths are interpreted as relative to the config file location.
# Relative paths are resolved relative to the current working directory.
location: foo/bar/geojson-schema.json

# A custom parser to use for files matching fileMatch
Expand All @@ -80,6 +84,7 @@ plugins:
# Plugins installed from NPM (or JSR) must be prefixed by "package:"
- "package:v8r-plugin-emoji-output"
# Plugins in the project dir must be prefixed by "file:"
# Relative paths are resolved relative to the current working directory.
- "file:./subdir/my-local-plugin.mjs"
```
Expand Down
30 changes: 7 additions & 23 deletions src/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const require = createRequire(import.meta.url);

import { cosmiconfig } from "cosmiconfig";
import decamelize from "decamelize";
import isUrl from "is-url";
import path from "path";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
Expand All @@ -17,27 +16,19 @@ import {
import logger from "./logger.js";
import { loadAllPlugins, resolveUserPlugins } from "./plugins.js";

function preProcessConfig(configFile) {
if (!configFile?.config?.customCatalog?.schemas) {
return;
}
for (const schema of configFile.config.customCatalog.schemas) {
if (!path.isAbsolute(schema.location) && !isUrl(schema.location)) {
schema.location = path.join(
path.dirname(configFile.filepath),
schema.location,
);
}
}
}

async function getCosmiConfig(cosmiconfigOptions) {
if (process.env.V8R_CONFIG_FILE) {
cosmiconfigOptions.searchPlaces = [process.env.V8R_CONFIG_FILE];
}
cosmiconfigOptions.stopDir = process.cwd();
const configFile = (await cosmiconfig("v8r", cosmiconfigOptions).search(
process.cwd(),
)) || { config: {} };
if (configFile.filepath) {
logger.info(`Loaded config file from ${getRelativeFilePath(configFile)}`);
logger.info(
`Patterns and relative paths will be resolved relative to current working directory: ${process.cwd()}`,
);
} else {
logger.info(`No config file found`);
}
Expand Down Expand Up @@ -200,7 +191,6 @@ async function bootstrap(argv, config, cosmiconfigOptions = {}) {
// we can finish validating and processing the config
validateConfigDocumentParsers(configFile, documentFormats);
validateConfigOutputFormats(configFile, outputFormats);
preProcessConfig(configFile);

// parse command line arguments
const args = parseArgs(argv, configFile, documentFormats, outputFormats);
Expand All @@ -213,10 +203,4 @@ async function bootstrap(argv, config, cosmiconfigOptions = {}) {
};
}

export {
bootstrap,
getDocumentFormats,
getOutputFormats,
parseArgs,
preProcessConfig,
};
export { bootstrap, getDocumentFormats, getOutputFormats, parseArgs };
57 changes: 2 additions & 55 deletions src/bootstrap.spec.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import assert from "assert";
import path from "path";
import {
bootstrap,
getDocumentFormats,
getOutputFormats,
parseArgs,
preProcessConfig,
} from "./bootstrap.js";
import { loadAllPlugins } from "./plugins.js";
import { setUp, tearDown, logContainsInfo } from "./test-helpers.js";
Expand Down Expand Up @@ -149,57 +147,6 @@ describe("parseArgs", function () {
});
});

describe("preProcessConfig", function () {
it("passes through absolute paths", function () {
const configFile = {
config: {
customCatalog: { schemas: [{ location: "/foo/bar/schema.json" }] },
},
filepath: "/home/fred/.v8rrc",
};
preProcessConfig(configFile);
assert.equal(
configFile.config.customCatalog.schemas[0].location,
"/foo/bar/schema.json",
);
});

it("passes through URLs", function () {
const configFile = {
config: {
customCatalog: {
schemas: [{ location: "https://example.com/schema.json" }],
},
},
filepath: "/home/fred/.v8rrc",
};
preProcessConfig(configFile);
assert.equal(
configFile.config.customCatalog.schemas[0].location,
"https://example.com/schema.json",
);
});

it("converts relative paths to absolute", function () {
const testCases = [
["schema.json", "/home/fred/schema.json"],
["../../schema.json", "/schema.json"],
["foo/bar/schema.json", "/home/fred/foo/bar/schema.json"],
];
for (const testCase of testCases) {
const configFile = {
config: { customCatalog: { schemas: [{ location: testCase[0] }] } },
filepath: "/home/fred/.v8rrc",
};
preProcessConfig(configFile);
assert.equal(
configFile.config.customCatalog.schemas[0].location,
testCase[1],
);
}
});
});

describe("getConfig", function () {
beforeEach(function () {
setUp();
Expand Down Expand Up @@ -246,7 +193,7 @@ describe("getConfig", function () {
{
name: "custom schema",
fileMatch: ["valid.json", "invalid.json"],
location: path.resolve("./testfiles/schemas/schema.json"),
location: "./testfiles/schemas/schema.json",
parser: "json5",
},
],
Expand Down Expand Up @@ -289,7 +236,7 @@ describe("getConfig", function () {
{
name: "custom schema",
fileMatch: ["valid.json", "invalid.json"],
location: path.resolve("./testfiles/schemas/schema.json"),
location: "./testfiles/schemas/schema.json",
parser: "json5",
},
],
Expand Down
2 changes: 1 addition & 1 deletion testfiles/configs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "custom schema",
"fileMatch": ["valid.json", "invalid.json"],
"location": "../schemas/schema.json",
"location": "./testfiles/schemas/schema.json",
"parser": "json5"
}
]
Expand Down

0 comments on commit cb721ae

Please sign in to comment.