Skip to content

Commit 400c5f9

Browse files
authored
feat!: add method getConfigStatus, update isFileIgnored (#7)
1 parent e42b15d commit 400c5f9

File tree

2 files changed

+1015
-276
lines changed

2 files changed

+1015
-276
lines changed

packages/config-array/src/config-array.js

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ const META_FIELDS = new Set(["name"]);
8080
*/
8181
const FILES_AND_IGNORES_SCHEMA = new ObjectSchema(filesAndIgnoresSchema);
8282

83+
// Precomputed constant objects returned by `ConfigArray.getConfigWithStatus`.
84+
85+
const CONFIG_WITH_STATUS_EXTERNAL = Object.freeze({ status: "external" });
86+
const CONFIG_WITH_STATUS_IGNORED = Object.freeze({ status: "ignored" });
87+
const CONFIG_WITH_STATUS_UNCONFIGURED = Object.freeze({
88+
status: "unconfigured",
89+
});
90+
8391
/**
8492
* Wrapper error for config validation errors that adds a name to the front of the
8593
* error message.
@@ -820,11 +828,14 @@ export class ConfigArray extends Array {
820828
}
821829

822830
/**
823-
* Returns the config object for a given file path.
831+
* Returns the config object for a given file path and a status that can be used to determine why a file has no config.
824832
* @param {string} filePath The complete path of a file to get a config for.
825-
* @returns {Object} The config object for this file.
833+
* @returns {{ config?: Object, status: "ignored"|"external"|"unconfigured"|"matched" }}
834+
* An object with an optional property `config` and property `status`.
835+
* `config` is the config object for the specified file as returned by {@linkcode ConfigArray.getConfig},
836+
* `status` a is one of the constants returned by {@linkcode ConfigArray.getConfigStatus}.
826837
*/
827-
getConfig(filePath) {
838+
getConfigWithStatus(filePath) {
828839
assertNormalized(this);
829840

830841
const cache = this[ConfigArraySymbol.configCache];
@@ -834,28 +845,35 @@ export class ConfigArray extends Array {
834845
return cache.get(filePath);
835846
}
836847

837-
let finalConfig;
848+
// check to see if the file is outside the base path
849+
850+
const relativeFilePath = path.relative(this.basePath, filePath);
851+
852+
if (relativeFilePath.startsWith("..")) {
853+
debug(`No config for file ${filePath} outside of base path`);
854+
855+
// cache and return result
856+
cache.set(filePath, CONFIG_WITH_STATUS_EXTERNAL);
857+
return CONFIG_WITH_STATUS_EXTERNAL;
858+
}
838859

839860
// next check to see if the file should be ignored
840861

841862
// check if this should be ignored due to its directory
842863
if (this.isDirectoryIgnored(path.dirname(filePath))) {
843864
debug(`Ignoring ${filePath} based on directory pattern`);
844865

845-
// cache and return result - finalConfig is undefined at this point
846-
cache.set(filePath, finalConfig);
847-
return finalConfig;
866+
// cache and return result
867+
cache.set(filePath, CONFIG_WITH_STATUS_IGNORED);
868+
return CONFIG_WITH_STATUS_IGNORED;
848869
}
849870

850-
// TODO: Maybe move elsewhere?
851-
const relativeFilePath = path.relative(this.basePath, filePath);
852-
853871
if (shouldIgnorePath(this.ignores, filePath, relativeFilePath)) {
854872
debug(`Ignoring ${filePath} based on file pattern`);
855873

856-
// cache and return result - finalConfig is undefined at this point
857-
cache.set(filePath, finalConfig);
858-
return finalConfig;
874+
// cache and return result
875+
cache.set(filePath, CONFIG_WITH_STATUS_IGNORED);
876+
return CONFIG_WITH_STATUS_IGNORED;
859877
}
860878

861879
// filePath isn't automatically ignored, so try to construct config
@@ -949,24 +967,25 @@ export class ConfigArray extends Array {
949967
if (!matchFound) {
950968
debug(`No matching configs found for ${filePath}`);
951969

952-
// cache and return result - finalConfig is undefined at this point
953-
cache.set(filePath, finalConfig);
954-
return finalConfig;
970+
// cache and return result
971+
cache.set(filePath, CONFIG_WITH_STATUS_UNCONFIGURED);
972+
return CONFIG_WITH_STATUS_UNCONFIGURED;
955973
}
956974

957975
// check to see if there is a config cached by indices
958-
finalConfig = cache.get(matchingConfigIndices.toString());
976+
const indicesKey = matchingConfigIndices.toString();
977+
let configWithStatus = cache.get(indicesKey);
959978

960-
if (finalConfig) {
979+
if (configWithStatus) {
961980
// also store for filename for faster lookup next time
962-
cache.set(filePath, finalConfig);
981+
cache.set(filePath, configWithStatus);
963982

964-
return finalConfig;
983+
return configWithStatus;
965984
}
966985

967986
// otherwise construct the config
968987

969-
finalConfig = matchingConfigIndices.reduce((result, index) => {
988+
let finalConfig = matchingConfigIndices.reduce((result, index) => {
970989
try {
971990
return this[ConfigArraySymbol.schema].merge(
972991
result,
@@ -979,10 +998,36 @@ export class ConfigArray extends Array {
979998

980999
finalConfig = this[ConfigArraySymbol.finalizeConfig](finalConfig);
9811000

982-
cache.set(filePath, finalConfig);
983-
cache.set(matchingConfigIndices.toString(), finalConfig);
1001+
configWithStatus = Object.freeze({
1002+
config: finalConfig,
1003+
status: "matched",
1004+
});
1005+
cache.set(filePath, configWithStatus);
1006+
cache.set(indicesKey, configWithStatus);
1007+
1008+
return configWithStatus;
1009+
}
9841010

985-
return finalConfig;
1011+
/**
1012+
* Returns the config object for a given file path.
1013+
* @param {string} filePath The complete path of a file to get a config for.
1014+
* @returns {Object|undefined} The config object for this file or `undefined`.
1015+
*/
1016+
getConfig(filePath) {
1017+
return this.getConfigWithStatus(filePath).config;
1018+
}
1019+
1020+
/**
1021+
* Determines whether a file has a config or why it doesn't.
1022+
* @param {string} filePath The complete path of the file to check.
1023+
* @returns {"ignored"|"external"|"unconfigured"|"matched"} One of the following values:
1024+
* * `"ignored"`: the file is ignored
1025+
* * `"external"`: the file is outside the base path
1026+
* * `"unconfigured"`: the file is not matched by any config
1027+
* * `"matched"`: the file has a matching config
1028+
*/
1029+
getConfigStatus(filePath) {
1030+
return this.getConfigWithStatus(filePath).status;
9861031
}
9871032

9881033
/**
@@ -1001,7 +1046,7 @@ export class ConfigArray extends Array {
10011046
* @returns {boolean} True if the path is ignored, false if not.
10021047
*/
10031048
isFileIgnored(filePath) {
1004-
return this.getConfig(filePath) === undefined;
1049+
return this.getConfigStatus(filePath) === "ignored";
10051050
}
10061051

10071052
/**

0 commit comments

Comments
 (0)