From 523d6b1c4e6d56b22f2fdcc95739856a771631ea Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Fri, 18 Dec 2020 14:35:45 +0000 Subject: [PATCH 1/2] feat: Owl config file & CLI with a config path option --- package.json | 1 + src/cli/build.ts | 7 ++++++- src/cli/config.ts | 52 +++++++++++++++++++++++++++++++++++++++++++++++ src/cli/index.ts | 13 ++++++++++-- src/cli/types.ts | 12 +++++++++++ tsconfig.json | 2 +- yarn.lock | 20 ++++++++++++++++++ 7 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 src/cli/config.ts diff --git a/package.json b/package.json index 3a8638cc..f4a9828e 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "testEnvironment": "node" }, "dependencies": { + "ajv": "^7.0.1", "yargs": "^16.2.0" }, "devDependencies": { diff --git a/src/cli/build.ts b/src/cli/build.ts index acc2ef2e..d6d596be 100644 --- a/src/cli/build.ts +++ b/src/cli/build.ts @@ -1,5 +1,10 @@ +import { getConfig } from './config'; import { BuildRunOptions } from './types'; export const buildHandler = async (args: BuildRunOptions) => { - console.log(`OWL will build for the ${args.platform} platform.`); + const config = await getConfig(args.config); + + console.log( + `OWL will build for the ${args.platform} platform. Config file: ${args.config}` + ); }; diff --git a/src/cli/config.ts b/src/cli/config.ts new file mode 100644 index 00000000..88552d07 --- /dev/null +++ b/src/cli/config.ts @@ -0,0 +1,52 @@ +import { promises as fs } from 'fs'; +import Ajv, { DefinedError, ErrorObject, JSONSchemaType } from 'ajv'; + +import { Config } from './types'; + +const configSschema: JSONSchemaType = { + type: 'object', + properties: { + ios: { + type: 'object', + properties: { + workspace: { type: 'string' }, + }, + required: ['workspace'], + nullable: true, + additionalProperties: false, + }, + android: { + type: 'object', + properties: {}, + required: [], + nullable: true, + additionalProperties: false, + }, + }, + required: [], + anyOf: [{ required: ['ios'] }, { required: ['android'] }], + additionalProperties: false, +}; + +const validateSchema = (config: {}): Promise => { + const ajv = new Ajv(); + const validate = ajv.compile(configSschema); + + return new Promise((resolve, reject) => { + if (validate(config)) { + resolve(config); + } else { + const errorMessage = validate + .errors!.map((err: ErrorObject) => `${err.schemaPath}: ${err.message}`) + .join(' '); + reject(errorMessage); + } + }); +}; + +export const getConfig = async (configPath: string): Promise => { + const configData = await fs.readFile(configPath, 'binary'); + const configString = Buffer.from(configData).toString(); + const parsedConfig = JSON.parse(configString); + return await validateSchema(parsedConfig); +}; diff --git a/src/cli/index.ts b/src/cli/index.ts index dc2054d8..58899433 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -8,12 +8,20 @@ import { runHandler } from './run'; const plaformOption: Options = { alias: 'p', - describe: 'Platform to build the app', + describe: 'Platform to build and run the app', demandOption: true, choices: ['ios', 'android'], }; +const configOption: Options = { + alias: 'c', + describe: 'Configuration file to be used', + type: 'string', + default: './owl.config.json', +}; + const builderOptions = { + config: configOption, platform: plaformOption, }; @@ -31,6 +39,7 @@ argv builder: builderOptions, handler: runHandler, }) - .help('h') + .help('help') .alias('h', 'help') + .showHelpOnFail(false, 'Specify --help for available options') .alias('v', 'version').argv; diff --git a/src/cli/types.ts b/src/cli/types.ts index f84b5ca5..67bbfac0 100644 --- a/src/cli/types.ts +++ b/src/cli/types.ts @@ -2,4 +2,16 @@ import { Arguments } from 'yargs'; export interface BuildRunOptions extends Arguments { platform: 'ios' | 'android'; + config: string; } + +type ConfigIOS = { + workspace: string; +}; + +type ConfigAndroid = {}; + +export type Config = { + ios?: ConfigIOS; + android?: ConfigAndroid; +}; diff --git a/tsconfig.json b/tsconfig.json index f0ea1599..99c069f0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,7 +27,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ + "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/yarn.lock b/yarn.lock index 725ced66..64bd2604 100644 --- a/yarn.lock +++ b/yarn.lock @@ -611,6 +611,16 @@ ajv@^6.12.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.0.1.tgz#d39ed49159672a91f796e2563e1e96984956e338" + integrity sha512-D2UYOXvDzGLVwld2/EyRu3xiJG885QUz2xS1phZzebYLPMPBFbPK4naXGDCtPltZoOG+I1+ZkNAJ65SJ3vqbsg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-escapes@^4.2.1: version "4.3.1" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" @@ -2293,6 +2303,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -2903,6 +2918,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + require-main-filename@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" From ec34d90d2a9b3c5a12f5c6406dff391af19b708f Mon Sep 17 00:00:00 2001 From: Emmanouil Konstantinidis Date: Fri, 18 Dec 2020 14:58:26 +0000 Subject: [PATCH 2/2] chore: Clean up and enable typechecking on CI --- .github/workflows/run-tests.yml | 3 ++ src/cli/build.ts | 2 + src/cli/config.ts | 65 +++++++++++++++++++-------------- tsconfig.json | 2 +- 4 files changed, 43 insertions(+), 29 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 16b27f1a..5281ef11 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -27,5 +27,8 @@ jobs: - name: Run Prettier (Check) run: yarn prettier:check + - name: Run Typescheck + run: yarn tsc --noEmit + - name: Run Unit Tests run: yarn test diff --git a/src/cli/build.ts b/src/cli/build.ts index d6d596be..e5efa661 100644 --- a/src/cli/build.ts +++ b/src/cli/build.ts @@ -4,6 +4,8 @@ import { BuildRunOptions } from './types'; export const buildHandler = async (args: BuildRunOptions) => { const config = await getConfig(args.config); + console.log('Configuration:', JSON.stringify(config, null, 2)); + console.log( `OWL will build for the ${args.platform} platform. Config file: ${args.config}` ); diff --git a/src/cli/config.ts b/src/cli/config.ts index 88552d07..fabeb523 100644 --- a/src/cli/config.ts +++ b/src/cli/config.ts @@ -1,34 +1,34 @@ import { promises as fs } from 'fs'; -import Ajv, { DefinedError, ErrorObject, JSONSchemaType } from 'ajv'; +import Ajv, { ErrorObject, JSONSchemaType } from 'ajv'; import { Config } from './types'; -const configSschema: JSONSchemaType = { - type: 'object', - properties: { - ios: { - type: 'object', - properties: { - workspace: { type: 'string' }, +const validateSchema = (config: {}): Promise => { + const configSschema: JSONSchemaType = { + type: 'object', + properties: { + ios: { + type: 'object', + properties: { + workspace: { type: 'string' }, + }, + required: ['workspace'], + nullable: true, + additionalProperties: false, + }, + android: { + type: 'object', + properties: {}, + required: [], + nullable: true, + additionalProperties: false, }, - required: ['workspace'], - nullable: true, - additionalProperties: false, - }, - android: { - type: 'object', - properties: {}, - required: [], - nullable: true, - additionalProperties: false, }, - }, - required: [], - anyOf: [{ required: ['ios'] }, { required: ['android'] }], - additionalProperties: false, -}; + required: [], + anyOf: [{ required: ['ios'] }, { required: ['android'] }], + additionalProperties: false, + }; -const validateSchema = (config: {}): Promise => { const ajv = new Ajv(); const validate = ajv.compile(configSschema); @@ -44,9 +44,18 @@ const validateSchema = (config: {}): Promise => { }); }; +const readConfigFile = async (configPath: string) => { + try { + const configData = await fs.readFile(configPath, 'binary'); + const configString = Buffer.from(configData).toString(); + const parsedConfig = JSON.parse(configString); + return parsedConfig; + } catch (err) { + throw new Error(`Could not load the config at ${configPath}`); + } +}; + export const getConfig = async (configPath: string): Promise => { - const configData = await fs.readFile(configPath, 'binary'); - const configString = Buffer.from(configData).toString(); - const parsedConfig = JSON.parse(configString); - return await validateSchema(parsedConfig); + const config = await readConfigFile(configPath); + return await validateSchema(config); }; diff --git a/tsconfig.json b/tsconfig.json index 99c069f0..c6d3704d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -35,7 +35,7 @@ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ + "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */