-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to create directory config files (#40)
## Summary: Users will be able to add files with the name `*graphql-flow.config.js` with a subset of the config fields (`options`, `excludes`) in order to have different behavior in that directory and its subdirectories. Another field, `extends`, takes the path of another sub-config (or the root config) and will use the extended config as a base to add or replace option fields and add new excludes. This is the first step in adding the ability to export robust flow enums, which we want to limit as to not disrupt other teams. Issue: LP-11796 ## Test plan: Thoroughly unit tested. Add `graphql-flow.config.js` with different options to any subdirectory and re-run `graphql-flow`. Author: nedredmond Reviewers: jaredly Required Reviewers: Approved By: jaredly Checks: ✅ Lint & Test (ubuntu-latest, 16.x) Pull Request URL: #40
- Loading branch information
1 parent
cbb165c
commit 5078624
Showing
7 changed files
with
295 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@khanacademy/graphql-flow': minor | ||
--- | ||
|
||
Users can add files with the name ending in `graphql-flow.config.js` with a subset of the config fields (`options`, `excludes`) in order to have more granular control of the behavior. Another field, `extends`, takes the path of another config file to use as a base and extends/overrides fields. If no `extends` is provided, the file completely overwrites any other config files (as far as `options` and `excludes`). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import {loadDirConfigFiles} from '../config'; | ||
|
||
import fs from 'fs'; | ||
jest.mock('fs'); | ||
|
||
const filesResponse = `javascript/discussion-package/components/graphql-flow.config.json | ||
javascript/discussion-package/graphql-flow.config.json | ||
`; | ||
const rootConfigPath = './dev/graphql-flow/config.json'; | ||
const mockRootConfig = { | ||
path: rootConfigPath, | ||
config: { | ||
options: { | ||
splitTypes: true, | ||
readOnlyArray: false, | ||
}, | ||
excludes: ['this one', 'that one'], | ||
schemaFilePath: 'this/is/a/path.graphql', | ||
dumpOperations: '', | ||
}, | ||
}; | ||
const firstFileFixture = { | ||
extends: 'javascript/discussion-package/graphql-flow.config.json', | ||
options: { | ||
splitTypes: false, | ||
}, | ||
excludes: ['that one'], | ||
}; | ||
const secondFileFixture = { | ||
extends: rootConfigPath, | ||
options: { | ||
readOnlyArray: true, | ||
}, | ||
excludes: ['another one'], | ||
}; | ||
|
||
describe('loading subconfigs', () => { | ||
it('should properly extend', () => { | ||
// eslint-disable-next-line flowtype-errors/uncovered | ||
fs.readFileSync | ||
.mockReturnValueOnce(JSON.stringify(firstFileFixture)) | ||
.mockReturnValueOnce(JSON.stringify(secondFileFixture)); | ||
|
||
const dirConfigMap = loadDirConfigFiles(filesResponse, mockRootConfig); | ||
|
||
const paths = Object.keys(dirConfigMap); | ||
const subConfig = dirConfigMap[paths[0]]; | ||
const deeperConfig = dirConfigMap[paths[1]]; | ||
|
||
expect(paths).toHaveLength(2); | ||
|
||
expect(subConfig.options.splitTypes).toBe(true); | ||
expect(subConfig.options.readOnlyArray).toBe(true); | ||
expect(subConfig.excludes.length).toBe(3); | ||
|
||
expect(deeperConfig.options.splitTypes).toBe(false); | ||
expect(subConfig.options.readOnlyArray).toBe(true); | ||
expect(subConfig.excludes.length).toBe(3); | ||
}); | ||
it('should properly overwrite', () => { | ||
// eslint-disable-next-line flowtype-errors/uncovered | ||
fs.readFileSync | ||
.mockReturnValueOnce( | ||
JSON.stringify({ | ||
options: {}, | ||
excludes: ['some other one'], | ||
}), | ||
) | ||
.mockReturnValueOnce( | ||
JSON.stringify({ | ||
options: { | ||
splitTypes: false, | ||
}, | ||
excludes: ['a completely different one one'], | ||
}), | ||
); | ||
|
||
const dirConfigMap = loadDirConfigFiles(filesResponse, mockRootConfig); | ||
|
||
const paths = Object.keys(dirConfigMap); | ||
const subConfig = dirConfigMap[paths[0]]; | ||
const deeperConfig = dirConfigMap[paths[1]]; | ||
|
||
expect(paths).toHaveLength(2); | ||
|
||
expect(subConfig.options.splitTypes).toBe(undefined); | ||
expect(subConfig.options.readOnlyArray).toBe(undefined); | ||
expect(subConfig.excludes.length).toBe(1); | ||
|
||
expect(deeperConfig.options.splitTypes).toBe(false); | ||
expect(subConfig.options.readOnlyArray).toBe(undefined); | ||
expect(subConfig.excludes.length).toBe(1); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// @flow | ||
import {longestMatchingPath} from '../utils.js'; | ||
|
||
describe('longestMatchingPath', () => { | ||
const filePath = 'here/is/a/file/path.exe'; | ||
const subConfigPaths = [ | ||
'not/a/match', | ||
'here/is', | ||
'here/is/a/file/path', | ||
'here/is/a/file/path/that/is/the/longest', | ||
'here/is/a/file/path/longer', | ||
'here/is/a/file', // here's the one we want | ||
'here/is/a', | ||
]; | ||
it('returns expected', () => { | ||
const match = longestMatchingPath(filePath, subConfigPaths); | ||
expect(match).toBe('here/is/a/file'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// @flow | ||
import path from 'path'; | ||
|
||
export const longestMatchingPath = ( | ||
filePath: string, | ||
subConfigPaths: string[], | ||
): string => { | ||
const {dir} = path.parse(filePath); | ||
return subConfigPaths.reduce( | ||
(closest: string, key: string) => | ||
dir.includes(key) && closest.length < key.length ? key : closest, | ||
'', | ||
); | ||
}; |