-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
184 additions
and
18 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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,95 @@ | ||
import { promises as fs } from 'fs'; | ||
import path from 'path'; | ||
import { XmlFileConfigStore } from './XmlFile'; | ||
|
||
describe('XmlFileConfigStore', () => { | ||
const testXmlFilePath = path.join(__dirname, 'test.xml'); | ||
|
||
beforeEach(async () => { | ||
await fs.writeFile( | ||
testXmlFilePath, | ||
` | ||
<?xml version="1.1" encoding="UTF-8"?> | ||
<root> | ||
<config> | ||
<set>dev</set> | ||
<key>GREETING</key> | ||
<value>hey</value> | ||
</config> | ||
<config> | ||
<set>prod</set> | ||
<key>SUBJECT</key> | ||
<value>world</value> | ||
</config> | ||
</root> | ||
`, | ||
); | ||
}); | ||
|
||
afterEach(async () => { | ||
await fs.unlink(testXmlFilePath); | ||
}); | ||
|
||
test('should read configurations from XML file', async () => { | ||
const store = new XmlFileConfigStore({ path: testXmlFilePath }); | ||
const configs = await store.get([ | ||
{ set: 'dev', key: 'GREETING' }, | ||
{ set: 'prod', key: 'SUBJECT' }, | ||
]); | ||
|
||
expect(configs).toEqual([ | ||
{ set: 'dev', key: 'GREETING', value: 'hey' }, | ||
{ set: 'prod', key: 'SUBJECT', value: 'world' }, | ||
]); | ||
}); | ||
|
||
const writeConfigs = async (store: XmlFileConfigStore) => { | ||
const configsToWrite = [ | ||
{ set: 'dev', key: 'GREETING', value: 'hey' }, | ||
{ set: 'prod', key: 'SUBJECT', value: 'world' }, | ||
]; | ||
await store.set(configsToWrite); | ||
|
||
// * Read the file again to verify the write operation | ||
const newConfigs = await store.get([ | ||
{ set: 'dev', key: 'GREETING' }, | ||
{ set: 'prod', key: 'SUBJECT' }, | ||
]); | ||
expect(newConfigs).toEqual(configsToWrite); | ||
}; | ||
|
||
test('should write configurations to new XML file', async () => { | ||
await fs.unlink(testXmlFilePath); | ||
const store = new XmlFileConfigStore({ path: testXmlFilePath }); | ||
await store.init(); | ||
await writeConfigs(store); | ||
}); | ||
|
||
test('should write configurations to an existing XML file', async () => { | ||
const store = new XmlFileConfigStore({ path: testXmlFilePath }); | ||
await writeConfigs(store); | ||
}); | ||
|
||
test('should query new XML file dev configurations', async () => { | ||
await fs.unlink(testXmlFilePath); | ||
const store = new XmlFileConfigStore({ path: testXmlFilePath }); | ||
await store.init(); | ||
const queries = [{ set: 'dev', key: 'GREETING' }]; | ||
const results = await store.get(queries); | ||
expect(results).toEqual([]); | ||
}); | ||
|
||
test('should query global configurations', async () => { | ||
const store = new XmlFileConfigStore({ path: testXmlFilePath }); | ||
const queries = [{ set: 'dev', key: 'GREETING' }]; | ||
const results = await store.get(queries); | ||
expect(results).toEqual([{ set: 'dev', key: 'GREETING', value: 'hey' }]); | ||
}); | ||
|
||
test('should query configurations', async () => { | ||
const store = new XmlFileConfigStore({ path: testXmlFilePath }); | ||
const queries = [{ set: 'prod', key: 'SUBJECT' }]; | ||
const results = await store.get(queries); | ||
expect(results).toEqual([{ set: 'prod', key: 'SUBJECT', value: 'world' }]); | ||
}); | ||
}); |
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,33 @@ | ||
import xml2js from 'xml2js'; | ||
import { type Config } from '@configu/ts'; | ||
import { FileConfigStore } from './File'; | ||
|
||
export type XmlFileConfigStoreConfiguration = { path: string; builderOptions?: xml2js.BuilderOptions }; | ||
|
||
export class XmlFileConfigStore extends FileConfigStore { | ||
private builder: xml2js.Builder; | ||
constructor({ path, builderOptions }: XmlFileConfigStoreConfiguration) { | ||
const builder = new xml2js.Builder(builderOptions); | ||
const initialFileState = builder.buildObject({ root: { config: [] } }); | ||
super('xml-file', { path, initialFileState }); | ||
this.builder = builder; | ||
} | ||
|
||
parse(fileContent: string): Config[] { | ||
let output: Config[] = []; | ||
const parser = new xml2js.Parser({ explicitArray: false }); | ||
parser.parseString(fileContent, (error, result) => { | ||
if (error) { | ||
throw error; | ||
} | ||
output = result.root.config ?? []; | ||
}); | ||
|
||
return output; | ||
} | ||
|
||
stringify(nextConfigs: Config[]): string { | ||
const xmlObject = { root: { config: nextConfigs } }; | ||
return this.builder.buildObject(xmlObject); | ||
} | ||
} |
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