Skip to content
This repository has been archived by the owner on Oct 5, 2021. It is now read-only.

Commit

Permalink
Merge pull request #55 from zoehneto/config-file
Browse files Browse the repository at this point in the history
feat: config file [WIP]
  • Loading branch information
urish authored Apr 9, 2018
2 parents d9b532c + 9bb3152 commit d76e5dd
Show file tree
Hide file tree
Showing 17 changed files with 494 additions and 30 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
language: node_js
sudo: false
node_js:
- 6.4.0
- 8
- stable
script:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"typescript": "^2.8.1"
},
"engines": {
"node": ">= 6.4.0",
"node": ">= 8.0.0",
"yarn": ">= 1.3.2"
},
"jest": {
Expand Down
5 changes: 3 additions & 2 deletions packages/typewiz-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
"author": "Uri Shaked <uri@urishaked.com>",
"license": "MIT",
"scripts": {
"build": "rimraf dist && tsc && copyfiles -u 1 src/type-collector-snippet.ts dist",
"build": "rimraf dist && tsc && copyfiles -u 1 src/type-collector-snippet.ts src/typewiz.json dist",
"lint": "tslint -p .",
"prepublish": "yarn build"
},
"files": ["dist"],
"dependencies": {
"ajv": "^6.4.0",
"typescript": "^2.4.2"
},
"engines": {
"node": ">= 6.4.0"
"node": ">= 8.0.0"
}
}
238 changes: 238 additions & 0 deletions packages/typewiz-core/src/configuration-parser.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
import * as fs from 'fs';
import * as path from 'path';

let typewizConfig = '';
const mockFs = {
readFile: jest.fn(
(filePath: string, options: any, callback: (err: NodeJS.ErrnoException, data: string) => void) => {
if (
filePath === path.resolve('packages', 'typewiz-core', 'src', 'typewiz.json') ||
filePath === path.resolve('not-found-file.json')
) {
fs.readFile(filePath, options, callback);
} else {
callback(null, typewizConfig);
}
},
),
readFileSync: jest.fn((filePath: string, options: any) => {
if (
filePath === path.resolve('packages', 'typewiz-core', 'src', 'typewiz.json') ||
filePath === path.resolve('not-found-file.json')
) {
return fs.readFileSync(filePath, options);
} else {
return typewizConfig;
}
}),
};
jest.doMock('fs', () => mockFs);

import { ConfigurationParser } from './configuration-parser';

describe('ConfigurationParser', () => {
it('should handle a non-existing typewiz.json file by using an empty default config - async', async () => {
const configParser = new ConfigurationParser();
await configParser.parse('not-found-file.json');
});

it('should handle a non-existing typewiz.json file by using an empty default config - sync', () => {
const configParser = new ConfigurationParser();
configParser.parseSync('not-found-file.json');
});

it('should throw an error if given bad typewiz.json file', async () => {
await expect(
(() => {
typewizConfig = '<invalid json>';
const configParser = new ConfigurationParser();
return configParser.parse('test/typewiz.json');
})(),
).rejects.toThrow(`Could not parser configuration file: Unexpected token < in JSON at position 0`);
});

it('should throw an error if given a typewiz.json file with invalid properties', async () => {
await expect(
(() => {
typewizConfig = `
{
"commond": {
"rootDir": ".",
"tsConfig": "./tsconfig.json"
}
}
`;
const configParser = new ConfigurationParser();
return configParser.parse('test/typewiz.json');
})(),
).rejects.toThrow(`typewiz.json should NOT have additional properties`);
});

it('should parse a valid typewiz.json file with no options set', async () => {
typewizConfig = `
{
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
});

it('should parse a valid typewiz.json file with all options set', async () => {
typewizConfig = `
{
"common": {
"rootDir": ".",
"tsConfig": "./tsconfig.json"
},
"instrument": {
"instrumentCallExpressions": true,
"instrumentImplicitThis": true,
"skipTwizDeclarations": true
},
"applyTypes": {
"prefix": "TypeWiz |"
}
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
});

it('should return an ICompilerConfig if no configuration is specified', async () => {
await expect(
(async () => {
typewizConfig = `
{
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
return configParser.getCompilerOptions();
})(),
).resolves.toEqual({});
});

it('should return an ICompilerConfig if a configuration is specified - async', async () => {
await expect(
(async () => {
typewizConfig = `
{
"common": {
"rootDir": ".",
"tsConfig": "./tsconfig.json"
}
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
return configParser.getCompilerOptions();
})(),
).resolves.toEqual({
rootDir: path.resolve('test', '.'),
tsConfig: path.resolve('test', './tsconfig.json'),
});
});

it('should return an ICompilerConfig if a configuration is specified - sync', () => {
expect(
(() => {
typewizConfig = `
{
"common": {
"rootDir": ".",
"tsConfig": "./tsconfig.json"
}
}
`;
const configParser = new ConfigurationParser();
configParser.parseSync('test/typewiz.json');
return configParser.getCompilerOptions();
})(),
).toEqual({
rootDir: path.resolve('test', '.'),
tsConfig: path.resolve('test', './tsconfig.json'),
});
});

it('should return IInstrumentOptions if no configuration is specified', async () => {
await expect(
(async () => {
typewizConfig = `
{
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
return configParser.getInstrumentOptions();
})(),
).resolves.toEqual({});
});

it('should return IInstrumentOptions if a configuration is specified', async () => {
await expect(
(async () => {
typewizConfig = `
{
"common": {
"rootDir": ".",
"tsConfig": "./tsconfig.json"
},
"instrument": {
"instrumentCallExpressions": true,
"instrumentImplicitThis": true,
"skipTwizDeclarations": true
}
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
return configParser.getInstrumentOptions();
})(),
).resolves.toEqual({
instrumentCallExpressions: true,
instrumentImplicitThis: true,
rootDir: path.resolve('test', '.'),
skipTwizDeclarations: true,
tsConfig: path.resolve('test', './tsconfig.json'),
});
});

it('should return IApplyTypesOptions if no configuration is specified', async () => {
await expect(
(async () => {
typewizConfig = `
{
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
return configParser.getApplyTypesOptions();
})(),
).resolves.toEqual({});
});

it('should return IApplyTypesOptions if a configuration is specified', async () => {
await expect(
(async () => {
typewizConfig = `
{
"common": {
"rootDir": ".",
"tsConfig": "./tsconfig.json"
},
"applyTypes": {
"prefix": "TypeWiz |"
}
}
`;
const configParser = new ConfigurationParser();
await configParser.parse('test/typewiz.json');
return configParser.getApplyTypesOptions();
})(),
).resolves.toEqual({
prefix: 'TypeWiz |',
rootDir: path.resolve('test', '.'),
tsConfig: path.resolve('test', './tsconfig.json'),
});
});
});
78 changes: 78 additions & 0 deletions packages/typewiz-core/src/configuration-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as Ajv from 'ajv';
import * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
import * as util from 'util';
import { IApplyTypesOptions } from './apply-types';
import { ICompilerOptions } from './compiler-helper';
import { IInstrumentOptions } from './instrument';
const readFileAsync = util.promisify(fs.readFile);
const typewizConfigSchema = require('./typewiz.json'); // tslint:disable-line:no-var-requires

export class ConfigurationParser {
private typewizConfig: any;
private configurationPath: string | undefined;

public findConfigFile(cwd: string): string {
return ts.findConfigFile(cwd, ts.sys.fileExists, 'typewiz.json');
}

public async parse(configurationPath: string): Promise<void> {
let typewizConfigString;
try {
typewizConfigString = await readFileAsync(path.resolve(configurationPath), { encoding: 'utf8' });
this.configurationPath = path.resolve(configurationPath);
} catch (error) {
typewizConfigString = '{}';
}

this.parseConfig(typewizConfigString);
}

public parseSync(configurationPath: string): void {
let typewizConfigString;
try {
typewizConfigString = fs.readFileSync(path.resolve(configurationPath), { encoding: 'utf8' });
this.configurationPath = path.resolve(configurationPath);
} catch (error) {
typewizConfigString = '{}';
}

this.parseConfig(typewizConfigString);
}

public getCompilerOptions(): ICompilerOptions {
const compilerOptions: ICompilerOptions = { ...this.typewizConfig.common };
if (compilerOptions.rootDir && this.configurationPath) {
compilerOptions.rootDir = path.resolve(path.dirname(this.configurationPath), compilerOptions.rootDir);
}
if (compilerOptions.tsConfig && this.configurationPath) {
compilerOptions.tsConfig = path.resolve(path.dirname(this.configurationPath), compilerOptions.tsConfig);
}
return compilerOptions;
}

public getInstrumentOptions(): IInstrumentOptions {
return { ...this.getCompilerOptions(), ...this.typewizConfig.instrument };
}

public getApplyTypesOptions(): IApplyTypesOptions {
return { ...this.getCompilerOptions(), ...this.typewizConfig.applyTypes };
}

private parseConfig(typewizConfigString: string): void {
let typewizConfig;
try {
typewizConfig = JSON.parse(typewizConfigString);
} catch (error) {
throw new Error('Could not parser configuration file: ' + error.message);
}

const ajv = new Ajv();
const valid = ajv.validate(typewizConfigSchema, typewizConfig);
if (!valid) {
throw new Error(ajv.errorsText(ajv.errors, { dataVar: 'typewiz.json' }));
}
this.typewizConfig = typewizConfig;
}
}
2 changes: 1 addition & 1 deletion packages/typewiz-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './apply-types';
export * from './configuration-parser';
export * from './instrument';
export * from './node-register';
export * from './type-collector';
1 change: 1 addition & 0 deletions packages/typewiz-core/src/integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as vm from 'vm';
import { transpileSource, virtualCompilerHost } from './test-utils/transpile';

const mockFs = {
readFile: jest.fn(fs.readFile),
readFileSync: jest.fn(fs.readFileSync),
writeFileSync: jest.fn(fs.writeFileSync),
};
Expand Down
Loading

0 comments on commit d76e5dd

Please sign in to comment.