From 288aa3e83572b6b3db7f0d74bdb11f97d924b57e Mon Sep 17 00:00:00 2001 From: Willian Date: Thu, 6 Jun 2019 20:48:29 -0300 Subject: [PATCH 01/12] Update concordialang-ui-core --- dist/commands/generate.d.ts | 3 +- dist/commands/generate.js | 51 ++++++++++++--------- dist/generator.d.ts | 3 +- dist/generator.js | 82 ++++++++++++++++++---------------- dist/widgets/button.js | 39 ++++++++-------- dist/widgets/checkbox.d.ts | 3 +- dist/widgets/checkbox.js | 12 ++++- dist/widgets/input.d.ts | 2 +- dist/widgets/input.js | 72 +++++++++++++++++------------ dist/widgets/prop.d.ts | 1 + dist/widgets/prop.js | 56 ++++++++++++++++++----- dist/widgets/radio.d.ts | 6 +++ dist/widgets/radio.js | 28 ++++++++++++ dist/widgets/select.d.ts | 7 +++ dist/widgets/select.js | 30 +++++++++++++ dist/widgets/widget-factory.js | 28 +++++++----- oclif.manifest.json | 18 +++++++- package-lock.json | 53 +++++++++++++++------- package.json | 2 +- 19 files changed, 342 insertions(+), 154 deletions(-) create mode 100644 dist/widgets/radio.d.ts create mode 100644 dist/widgets/radio.js create mode 100644 dist/widgets/select.d.ts create mode 100644 dist/widgets/select.js diff --git a/dist/commands/generate.d.ts b/dist/commands/generate.d.ts index 730ea44..bd4c90c 100644 --- a/dist/commands/generate.d.ts +++ b/dist/commands/generate.d.ts @@ -3,7 +3,8 @@ export default class Generate extends Command { static description: string; static flags: { help: import("@oclif/parser/lib/flags").IBooleanFlag; - features: flags.IOptionFlag; + features: flags.IOptionFlag; + outputDir: flags.IOptionFlag; }; run(): Promise; } diff --git a/dist/commands/generate.js b/dist/commands/generate.js index d0674a5..9724772 100644 --- a/dist/commands/generate.js +++ b/dist/commands/generate.js @@ -1,25 +1,32 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const tslib_1 = require("tslib"); -const command_1 = require("@oclif/command"); -const fs = require("fs"); -const generator_1 = require("../generator"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const tslib_1 = require('tslib') +const command_1 = require('@oclif/command') +const fs = require('fs') +const generator_1 = require('../generator') class Generate extends command_1.Command { - run() { - return tslib_1.__awaiter(this, void 0, void 0, function* () { - const { flags } = this.parse(Generate); - if (flags.features) { - const processResult = JSON.parse(flags.features); - const generator = new generator_1.default(fs); - const result = yield generator.generate(processResult.features); - this.log(JSON.stringify(result)); - } - }); - } + run() { + return tslib_1.__awaiter(this, void 0, void 0, function*() { + const { flags } = this.parse(Generate) + if (flags.features) { + const processResult = JSON.parse(flags.features) + const generator = new generator_1.default(fs, flags.outputDir) + const result = yield generator.generate(processResult.features) + this.log(JSON.stringify(result)) + } + }) + } } -Generate.description = 'Generate html files'; +Generate.description = 'Generate html files' Generate.flags = { - help: command_1.flags.help({ char: 'h' }), - features: command_1.flags.string({ description: 'processed features from ast' }) -}; -exports.default = Generate; + help: command_1.flags.help({ char: 'h' }), + features: command_1.flags.string({ + description: 'processed features from ast', + required: true, + }), + outputDir: command_1.flags.string({ + description: 'location where output files will be saved', + required: true, + }), +} +exports.default = Generate diff --git a/dist/generator.d.ts b/dist/generator.d.ts index d45cbb2..e76df41 100644 --- a/dist/generator.d.ts +++ b/dist/generator.d.ts @@ -1,7 +1,8 @@ import { Feature, Prototyper } from 'concordialang-ui-core'; export default class Generator implements Prototyper { private _fs; - constructor(_fs?: any); + private _outputDir; + constructor(_fs: any, _outputDir: string); generate(features: Feature[]): Promise; private createHtmlFile; } diff --git a/dist/generator.js b/dist/generator.js index 441a542..a593805 100644 --- a/dist/generator.js +++ b/dist/generator.js @@ -1,41 +1,45 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const tslib_1 = require("tslib"); -const fs = require("fs"); -const util_1 = require("util"); -const widget_factory_1 = require("./widgets/widget-factory"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const tslib_1 = require('tslib') +const fs = require('fs') +const util_1 = require('util') +const path_1 = require('path') +const pretty = require('pretty') +const widget_factory_1 = require('./widgets/widget-factory') class Generator { - constructor(_fs = fs) { - this._fs = _fs; - } - generate(features) { - return tslib_1.__awaiter(this, void 0, void 0, function* () { - const factory = new widget_factory_1.default(); - let createFilePromises = []; - for (let feature of features) { - const widgets = []; - for (let element of feature.uiElements) { - const widget = factory.create(element); - widgets.push(widget); - } - const createFilePromise = this.createHtmlFile(feature.name, widgets); - createFilePromises.push(createFilePromise); - } - return Promise.all(createFilePromises); - }); - } - createHtmlFile(fileName, widgets) { - return tslib_1.__awaiter(this, void 0, void 0, function* () { - //TODO format content - let content = widgets.reduce((result, widget) => { - return result + widget.renderToString() + '\n'; - }, ''); - content = `
${content}
`; - const writeF = util_1.promisify(this._fs.writeFile); - const fullName = fileName + '.html'; - yield writeF(fullName, content); - return fullName; - }); - } + constructor(_fs = fs, _outputDir) { + this._fs = _fs + this._outputDir = _outputDir + } + generate(features) { + return tslib_1.__awaiter(this, void 0, void 0, function*() { + const factory = new widget_factory_1.default() + let createFilePromises = [] + for (let feature of features) { + const elements = feature.uiElements.map(uiElement => + factory.create(uiElement) + ) + createFilePromises.push( + this.createHtmlFile(feature.name, elements) + ) + } + return Promise.all(createFilePromises) + }) + } + createHtmlFile(fileName, widgets) { + return tslib_1.__awaiter(this, void 0, void 0, function*() { + let content = widgets.reduce((result, widget) => { + return result + widget.renderToString() + '\n' + }, '') + content = pretty(`
\n${content}
`, { ocd: true }) + const path = path_1.format({ + dir: this._outputDir, + name: fileName, + ext: '.html', + }) + yield util_1.promisify(fs.writeFile)(path, content) + return path + }) + } } -exports.default = Generator; +exports.default = Generator diff --git a/dist/widgets/button.js b/dist/widgets/button.js index 80456fa..8bb1d17 100644 --- a/dist/widgets/button.js +++ b/dist/widgets/button.js @@ -1,20 +1,23 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const concordialang_ui_core_1 = require("concordialang-ui-core"); -const prop_1 = require("./prop"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const concordialang_ui_core_1 = require('concordialang-ui-core') +const prop_1 = require('./prop') class Button extends concordialang_ui_core_1.Widget { - constructor(props, name) { - super(props, name); - // private readonly DATA_TYPES = ['button', 'submit', 'reset'] - this.VALID_PROPERTIES = ['id', 'disabled', 'value']; - } - renderToString() { - const inputType = this.getType(this.props.datatype); - const properties = prop_1.formatProperties(this.props, this.VALID_PROPERTIES); - return ``; - } - getType(datatype) { - return `type="${datatype || 'button'}"`; - } + constructor(props, name) { + super(props, name || '') + this.VALID_PROPERTIES = ['id', 'disabled', 'value'] + } + renderToString() { + // const inputType = this.getType(this.props.datatype as string) + const properties = prop_1.formatProperties( + this.props, + this.VALID_PROPERTIES + ) + // return `` + return `` + } + getType(datatype) { + return `type="${datatype || 'button'}"` + } } -exports.Button = Button; +exports.Button = Button diff --git a/dist/widgets/checkbox.d.ts b/dist/widgets/checkbox.d.ts index 16d2703..85c1f79 100644 --- a/dist/widgets/checkbox.d.ts +++ b/dist/widgets/checkbox.d.ts @@ -1,5 +1,6 @@ import { Widget } from 'concordialang-ui-core'; export declare class Checkbox extends Widget { - constructor(props: any, name?: string); + private readonly VALID_PROPERTIES; + constructor(props: any, name: string); renderToString(): string; } diff --git a/dist/widgets/checkbox.js b/dist/widgets/checkbox.js index c9be1d9..89f082e 100644 --- a/dist/widgets/checkbox.js +++ b/dist/widgets/checkbox.js @@ -1,12 +1,22 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') +const prop_1 = require('./prop') class Checkbox extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name) + this.VALID_PROPERTIES = ['value', 'required'] } renderToString() { - return `TESTE` + const properties = prop_1.formatProperties( + this.props, + this.VALID_PROPERTIES + ) + if (properties) + return `
\n${ + this.name + }\n
` + return `
\n${this.name}\n
` } } exports.Checkbox = Checkbox diff --git a/dist/widgets/input.d.ts b/dist/widgets/input.d.ts index 8d0d93c..ecb4c44 100644 --- a/dist/widgets/input.d.ts +++ b/dist/widgets/input.d.ts @@ -1,7 +1,7 @@ import { Widget } from 'concordialang-ui-core'; export declare class Input extends Widget { private readonly VALID_PROPERTIES; - constructor(props: any, name?: string); + constructor(props: any, name: string); renderToString(): string; private getType; private typeForDataType; diff --git a/dist/widgets/input.js b/dist/widgets/input.js index 2fd88dd..229a3a8 100644 --- a/dist/widgets/input.js +++ b/dist/widgets/input.js @@ -1,30 +1,46 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const concordialang_ui_core_1 = require("concordialang-ui-core"); -const prop_1 = require("./prop"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const concordialang_ui_core_1 = require('concordialang-ui-core') +const prop_1 = require('./prop') class Input extends concordialang_ui_core_1.Widget { - constructor(props, name) { - super(props, name); - this.VALID_PROPERTIES = ['id', 'editable', 'minlength', 'maxlength', 'required', 'format']; - } - renderToString() { - const inputType = this.getType(this.props.datatype); - const properties = prop_1.formatProperties(this.props, this.VALID_PROPERTIES); - const label = (this.name) ? `` : ''; - return `${label} `; - } - getType(datatype) { - const typeProperty = this.typeForDataType(datatype); - return `type="${typeProperty}"`; - } - typeForDataType(datatype) { - switch (datatype) { - case "integer" /* INTEGER */: - case "double" /* DOUBLE */: return 'number'; - case "time" /* TIME */: return 'time'; - case "datetime" /* DATETIME */: return 'datetime-local'; - } - return 'text'; - } + constructor(props, name) { + super(props, name) + this.VALID_PROPERTIES = [ + 'id', + 'editable', + 'minlength', + 'maxlength', + 'required', + 'format', + ] + } + renderToString() { + const inputType = this.getType(this.props.datatype) + const properties = prop_1.formatProperties( + this.props, + this.VALID_PROPERTIES + ) + const input = properties + ? `\n` + : `\n` + const label = prop_1.createLabel(this.name, this.props.id.toString()) + return `
\n${label + input}
` + } + getType(datatype) { + const typeProperty = this.typeForDataType(datatype) + return `type="${typeProperty}"` + } + typeForDataType(datatype) { + switch (datatype) { + case 'integer' /* INTEGER */: + case 'double' /* DOUBLE */: + return 'number' + case 'time' /* TIME */: + return 'time' + case 'datetime' /* DATETIME */: + return 'datetime-local' + } + return 'text' + } } -exports.Input = Input; +exports.Input = Input diff --git a/dist/widgets/prop.d.ts b/dist/widgets/prop.d.ts index c409969..62d4fef 100644 --- a/dist/widgets/prop.d.ts +++ b/dist/widgets/prop.d.ts @@ -1 +1,2 @@ export declare function formatProperties(props: any, validProperties: string[]): string; +export declare function createLabel(name: string, id: string): string; diff --git a/dist/widgets/prop.js b/dist/widgets/prop.js index a394968..074abb0 100644 --- a/dist/widgets/prop.js +++ b/dist/widgets/prop.js @@ -1,12 +1,48 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) function formatProperties(props, validProperties) { - const getFormattedProp = (key) => `${key}="${props[key]}"`; - const formatValid = function (result, key) { - return validProperties.includes(key) - ? result + getFormattedProp(key) - : result; - }; - return Object.keys(props).reduce(formatValid, ''); + const translateProp = key => { + switch (key) { + case 'format': + return 'pattern' + default: + return key + } + } + const getFormattedProp = key => { + let value = props[key] + const invalidIdPattern = /^\/\// + if (key === 'id') { + let newKey = key + if (!invalidIdPattern.test(value)) { + const validIdPattern = /^#|~/ + const validClassPattern = /^\./ + if (validIdPattern.test(value)) { + value = value.toString().replace(validIdPattern, '') + } else if (validClassPattern.test(value)) { + newKey = 'class' + value = value.toString().replace(validClassPattern, '') + } + return `${translateProp(newKey)}="${value}"` + } + } + return `${translateProp(key)}="${value}"` + } + const formatValid = (result, prop) => { + return validProperties.includes(prop) + ? result + getFormattedProp(prop) + ' ' + : result + } + return Object.keys(props) + .reduce(formatValid, '') + .trimRight() } -exports.formatProperties = formatProperties; +exports.formatProperties = formatProperties +function createLabel(name, id) { + const validIdPattern = /^(#|~|\d|\w).*/ + const labelFor = validIdPattern.test(id) + ? `for="${id.replace(/^#|~/, '')}"` + : '' + return `\n` +} +exports.createLabel = createLabel diff --git a/dist/widgets/radio.d.ts b/dist/widgets/radio.d.ts new file mode 100644 index 0000000..28483b5 --- /dev/null +++ b/dist/widgets/radio.d.ts @@ -0,0 +1,6 @@ +import { Widget } from 'concordialang-ui-core'; +export declare class Radio extends Widget { + private readonly VALID_PROPERTIES; + constructor(props: any, name: string); + renderToString(): string; +} diff --git a/dist/widgets/radio.js b/dist/widgets/radio.js new file mode 100644 index 0000000..7ca33f8 --- /dev/null +++ b/dist/widgets/radio.js @@ -0,0 +1,28 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const concordialang_ui_core_1 = require('concordialang-ui-core') +const prop_1 = require('./prop') +class Radio extends concordialang_ui_core_1.Widget { + constructor(props, name) { + super(props, name) + this.VALID_PROPERTIES = ['value'] + } + renderToString() { + const properties = prop_1.formatProperties( + this.props, + this.VALID_PROPERTIES + ) + let inputs = [] + const label = prop_1.createLabel(this.name, this.props.id.toString()) + const inputName = this.name.toLowerCase() + if (properties) { + for (let value of this.props.value) { + let input = `${value}` + inputs.push(input) + } + return `
\n${label + inputs.join('\n')}\n
` + } + return '
\n\n
' + } +} +exports.Radio = Radio diff --git a/dist/widgets/select.d.ts b/dist/widgets/select.d.ts new file mode 100644 index 0000000..31b574c --- /dev/null +++ b/dist/widgets/select.d.ts @@ -0,0 +1,7 @@ +import { Widget } from 'concordialang-ui-core'; +export declare class Select extends Widget { + private readonly VALID_PROPERTIES; + constructor(props: any, name: string); + renderToString(): string; + private getOptions; +} diff --git a/dist/widgets/select.js b/dist/widgets/select.js new file mode 100644 index 0000000..0e6c0f1 --- /dev/null +++ b/dist/widgets/select.js @@ -0,0 +1,30 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const concordialang_ui_core_1 = require('concordialang-ui-core') +const prop_1 = require('./prop') +class Select extends concordialang_ui_core_1.Widget { + constructor(props, name) { + super(props, name) + this.VALID_PROPERTIES = ['id', 'required'] + } + renderToString() { + const properties = prop_1.formatProperties( + this.props, + this.VALID_PROPERTIES + ) + if (!properties) return '
\n\n
' + const options = this.getOptions() + const select = `\n` + const label = prop_1.createLabel(this.name, this.props.id.toString()) + return `
\n${label + select}
` + } + getOptions() { + let options = [] + for (let value of this.props.value) { + let option = `` + options.push(option) + } + return options.join('\n') + } +} +exports.Select = Select diff --git a/dist/widgets/widget-factory.js b/dist/widgets/widget-factory.js index 2543978..e261294 100644 --- a/dist/widgets/widget-factory.js +++ b/dist/widgets/widget-factory.js @@ -1,14 +1,18 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const button_1 = require("./button"); -const input_1 = require("./input"); +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const button_1 = require('./button') class WidgetFactory { - create(element) { - switch (element.widget) { - case "textbox" /* TEXTBOX */: return new input_1.Input(element.props, element.name); - case "button" /* BUTTON */: return new button_1.Button(element.props, element.name); - default: return new input_1.Input(null); - } - } + create(element) { + switch (element.widget) { + //case Widgets.TEXTBOX: return new Input(element.props, element.name) + case 'button' /* BUTTON */: + return new button_1.Button(element.props, element.name) + //case Widgets.CHECKBOX: return new Checkbox(element.props, element.name) + //case Widgets.RADIO: return new Radio(element.props, element.name) + //case Widgets.SELECT: return new Select(element.props, element.name) + default: + throw new Error(`Invalid widget type: ${element.widget}`) + } + } } -exports.default = WidgetFactory; +exports.default = WidgetFactory diff --git a/oclif.manifest.json b/oclif.manifest.json index 59eaeb3..811c12c 100644 --- a/oclif.manifest.json +++ b/oclif.manifest.json @@ -18,7 +18,14 @@ "features": { "name": "features", "type": "option", - "description": "processed features from ast" + "description": "processed features from ast", + "required": true + }, + "outputDir": { + "name": "outputDir", + "type": "option", + "description": "location where output files will be saved", + "required": true } }, "args": [] @@ -40,7 +47,14 @@ "features": { "name": "features", "type": "option", - "description": "processed features from ast" + "description": "processed features from ast", + "required": true + }, + "outputDir": { + "name": "outputDir", + "type": "option", + "description": "location where output files will be saved", + "required": true } }, "args": [] diff --git a/package-lock.json b/package-lock.json index 7d8a9e1..ac1c4d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1857,9 +1857,9 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concordialang-ui-core": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/concordialang-ui-core/-/concordialang-ui-core-0.2.0.tgz", - "integrity": "sha512-ws0Gyi9SYgV5QififA5I4XlcBIzwBnix27N16YfwZhFMHLnsKTXRf+Du7fuu3yEIpbnlNDCSRYwLj41dPKgugA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/concordialang-ui-core/-/concordialang-ui-core-0.2.2.tgz", + "integrity": "sha512-1EONXdRmNQLPzVHxuMKGiY2dLejTbPJA3SiLhEKqqJNWMWle+MGsYGTMnsxFIxh7w+YTOifkuxg8DS6RjmfDVg==", "requires": { "database-js": "^3.0.8", "database-js-json": "^1.2.1" @@ -2003,9 +2003,9 @@ } }, "database-js": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/database-js/-/database-js-3.0.8.tgz", - "integrity": "sha512-G2RZEXMK+DuIvviYs02xMViJ4gtc+VIXokoE+f2R4uyHXI3odDYSY3zqPoteFPnHzVDsnnrx336/yjOdXkl6Vg==" + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/database-js/-/database-js-3.0.9.tgz", + "integrity": "sha512-khaHbjOFLQLWSPm65Ix3G86iAXTLGof1JUQUDY/knuR0kBmN9Z8Lb7HXAl8FD9bBpIPRJ9Bh2dPKcWv7p3AwJw==" }, "database-js-json": { "version": "1.2.1", @@ -2741,7 +2741,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2762,12 +2763,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2782,17 +2785,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2909,7 +2915,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2921,6 +2928,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2935,6 +2943,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2942,12 +2951,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2966,6 +2977,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -3046,7 +3058,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3058,6 +3071,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3143,7 +3157,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3179,6 +3194,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3198,6 +3214,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3241,12 +3258,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/package.json b/package.json index 8f19a72..1e28938 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "dependencies": { "@oclif/command": "^1.5.12", "@oclif/config": "^1.12.12", - "concordialang-ui-core": "^0.2.0", + "concordialang-ui-core": "^0.2.2", "pretty": "^2.0.0", "tslib": "^1.9.3" }, From e394ee82fefbd841b74679c1f14afe05f573dae5 Mon Sep 17 00:00:00 2001 From: Willian Date: Thu, 6 Jun 2019 20:49:23 -0300 Subject: [PATCH 02/12] Run build script on pre-commit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e28938..4214247 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ }, "husky": { "hooks": { - "pre-commit": "lint-staged" + "pre-commit": "npm run build && lint-staged" } }, "lint-staged": { From 678bb4baf715c08021a1f2766ecbf46d43f57461 Mon Sep 17 00:00:00 2001 From: Willian Date: Sat, 8 Jun 2019 12:04:04 -0300 Subject: [PATCH 03/12] Create input elements based on custom definitions file --- dist/generator.js | 19 ++- dist/interfaces/custom_config.d.ts | 15 ++ dist/interfaces/custom_config.js | 7 + dist/utils/config_loader.d.ts | 6 + dist/utils/config_loader.js | 12 ++ dist/utils/create_label.d.ts | 1 + dist/utils/create_label.js | 10 ++ dist/utils/index.d.ts | 2 + dist/utils/index.js | 5 + dist/{widgets => utils}/prop.d.ts | 1 - dist/{widgets => utils}/prop.js | 9 +- dist/widgets/button.js | 4 +- dist/widgets/checkbox.js | 5 +- dist/widgets/index.d.ts | 4 - dist/widgets/index.js | 7 - dist/widgets/input.d.ts | 7 +- dist/widgets/input.js | 64 ++++++-- dist/widgets/radio.js | 7 +- dist/widgets/select.js | 7 +- dist/widgets/widget-factory.d.ts | 4 + dist/widgets/widget-factory.js | 31 +++- package-lock.json | 235 ++++++----------------------- package.json | 4 +- src/generator.ts | 17 ++- src/interfaces/custom_config.ts | 18 +++ src/utils/config_loader.ts | 10 ++ src/utils/create_label.ts | 5 + src/utils/index.ts | 2 + src/{widgets => utils}/prop.ts | 13 +- src/widgets/button.ts | 2 +- src/widgets/checkbox.ts | 3 +- src/widgets/index.ts | 4 - src/widgets/input.ts | 52 +++++-- src/widgets/radio.ts | 3 +- src/widgets/select.ts | 3 +- src/widgets/widget-factory.ts | 13 +- 36 files changed, 324 insertions(+), 287 deletions(-) create mode 100644 dist/interfaces/custom_config.d.ts create mode 100644 dist/interfaces/custom_config.js create mode 100644 dist/utils/config_loader.d.ts create mode 100644 dist/utils/config_loader.js create mode 100644 dist/utils/create_label.d.ts create mode 100644 dist/utils/create_label.js create mode 100644 dist/utils/index.d.ts create mode 100644 dist/utils/index.js rename dist/{widgets => utils}/prop.d.ts (55%) rename dist/{widgets => utils}/prop.js (81%) delete mode 100644 dist/widgets/index.d.ts delete mode 100644 dist/widgets/index.js create mode 100644 src/interfaces/custom_config.ts create mode 100644 src/utils/config_loader.ts create mode 100644 src/utils/create_label.ts create mode 100644 src/utils/index.ts rename src/{widgets => utils}/prop.ts (83%) delete mode 100644 src/widgets/index.ts diff --git a/dist/generator.js b/dist/generator.js index a593805..cfe5eac 100644 --- a/dist/generator.js +++ b/dist/generator.js @@ -4,8 +4,11 @@ const tslib_1 = require('tslib') const fs = require('fs') const util_1 = require('util') const path_1 = require('path') -const pretty = require('pretty') +const prettier = require('prettier') +const cosmiconfig = require('cosmiconfig') const widget_factory_1 = require('./widgets/widget-factory') +// TODO: use "export default" +const config_loader_1 = require('./utils/config_loader') class Generator { constructor(_fs = fs, _outputDir) { this._fs = _fs @@ -13,7 +16,12 @@ class Generator { } generate(features) { return tslib_1.__awaiter(this, void 0, void 0, function*() { - const factory = new widget_factory_1.default() + // search for a ".configrc.json" + // TODO: replace "config" with the CLI name + const explorer = cosmiconfig('config') + let config = explorer.searchSync() + const configLoader = new config_loader_1.ConfigLoader(config) + const factory = new widget_factory_1.default(configLoader) let createFilePromises = [] for (let feature of features) { const elements = feature.uiElements.map(uiElement => @@ -29,9 +37,12 @@ class Generator { createHtmlFile(fileName, widgets) { return tslib_1.__awaiter(this, void 0, void 0, function*() { let content = widgets.reduce((result, widget) => { - return result + widget.renderToString() + '\n' + return result + widget.renderToString() }, '') - content = pretty(`
\n${content}
`, { ocd: true }) + content = prettier.format(`
\n${content}
`, { + parser: 'html', + htmlWhitespaceSensitivity: 'ignore', + }) const path = path_1.format({ dir: this._outputDir, name: fileName, diff --git a/dist/interfaces/custom_config.d.ts b/dist/interfaces/custom_config.d.ts new file mode 100644 index 0000000..bdcbf22 --- /dev/null +++ b/dist/interfaces/custom_config.d.ts @@ -0,0 +1,15 @@ +export interface CustomConfig { + widgets?: { + input?: WidgetConfig; + }; +} +export interface WidgetConfig { + opening: string; + closure?: string; + header?: string; + footer?: string; +} +export declare const WIDGET_OPENING = "opening"; +export declare const WIDGET_CLOSURE = "closure"; +export declare const WIDGET_WRAPPER_OPENING = "header"; +export declare const WIDGET_WRAPPER_CLOSURE = "footer"; diff --git a/dist/interfaces/custom_config.js b/dist/interfaces/custom_config.js new file mode 100644 index 0000000..e6dd1cb --- /dev/null +++ b/dist/interfaces/custom_config.js @@ -0,0 +1,7 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +// path for properties in WidgetConfig to by used in lodash "get" method +exports.WIDGET_OPENING = 'opening' +exports.WIDGET_CLOSURE = 'closure' +exports.WIDGET_WRAPPER_OPENING = 'header' +exports.WIDGET_WRAPPER_CLOSURE = 'footer' diff --git a/dist/utils/config_loader.d.ts b/dist/utils/config_loader.d.ts new file mode 100644 index 0000000..24fa186 --- /dev/null +++ b/dist/utils/config_loader.d.ts @@ -0,0 +1,6 @@ +import { CustomConfig, WidgetConfig } from '../interfaces/custom_config'; +export declare class ConfigLoader { + private _config; + constructor(_config: CustomConfig); + getInputDefinition(): WidgetConfig; +} diff --git a/dist/utils/config_loader.js b/dist/utils/config_loader.js new file mode 100644 index 0000000..6fdcea5 --- /dev/null +++ b/dist/utils/config_loader.js @@ -0,0 +1,12 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const lodash_1 = require('lodash') +class ConfigLoader { + constructor(_config) { + this._config = _config + } + getInputDefinition() { + return lodash_1.get(this._config, 'config.widgets.input') + } +} +exports.ConfigLoader = ConfigLoader diff --git a/dist/utils/create_label.d.ts b/dist/utils/create_label.d.ts new file mode 100644 index 0000000..d914e3a --- /dev/null +++ b/dist/utils/create_label.d.ts @@ -0,0 +1 @@ +export declare function createLabel(name: string, id: string): string; diff --git a/dist/utils/create_label.js b/dist/utils/create_label.js new file mode 100644 index 0000000..125f5ce --- /dev/null +++ b/dist/utils/create_label.js @@ -0,0 +1,10 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +function createLabel(name, id) { + const validIdPattern = /^(#|~|\d|\w).*/ + const labelFor = validIdPattern.test(id) + ? `for="${id.replace(/^#|~/, '')}"` + : '' + return `` +} +exports.createLabel = createLabel diff --git a/dist/utils/index.d.ts b/dist/utils/index.d.ts new file mode 100644 index 0000000..f812114 --- /dev/null +++ b/dist/utils/index.d.ts @@ -0,0 +1,2 @@ +export * from './prop'; +export * from './create_label'; diff --git a/dist/utils/index.js b/dist/utils/index.js new file mode 100644 index 0000000..dfd1a2f --- /dev/null +++ b/dist/utils/index.js @@ -0,0 +1,5 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +const tslib_1 = require('tslib') +tslib_1.__exportStar(require('./prop'), exports) +tslib_1.__exportStar(require('./create_label'), exports) diff --git a/dist/widgets/prop.d.ts b/dist/utils/prop.d.ts similarity index 55% rename from dist/widgets/prop.d.ts rename to dist/utils/prop.d.ts index 62d4fef..c409969 100644 --- a/dist/widgets/prop.d.ts +++ b/dist/utils/prop.d.ts @@ -1,2 +1 @@ export declare function formatProperties(props: any, validProperties: string[]): string; -export declare function createLabel(name: string, id: string): string; diff --git a/dist/widgets/prop.js b/dist/utils/prop.js similarity index 81% rename from dist/widgets/prop.js rename to dist/utils/prop.js index 074abb0..b4c1c4e 100644 --- a/dist/widgets/prop.js +++ b/dist/utils/prop.js @@ -14,6 +14,7 @@ function formatProperties(props, validProperties) { const invalidIdPattern = /^\/\// if (key === 'id') { let newKey = key + // TODO: replace test wit str.match(pattern) if (!invalidIdPattern.test(value)) { const validIdPattern = /^#|~/ const validClassPattern = /^\./ @@ -38,11 +39,3 @@ function formatProperties(props, validProperties) { .trimRight() } exports.formatProperties = formatProperties -function createLabel(name, id) { - const validIdPattern = /^(#|~|\d|\w).*/ - const labelFor = validIdPattern.test(id) - ? `for="${id.replace(/^#|~/, '')}"` - : '' - return `\n` -} -exports.createLabel = createLabel diff --git a/dist/widgets/button.js b/dist/widgets/button.js index 8bb1d17..f40176d 100644 --- a/dist/widgets/button.js +++ b/dist/widgets/button.js @@ -1,7 +1,7 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const prop_1 = require('./prop') +const utils_1 = require('../utils') class Button extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name || '') @@ -9,7 +9,7 @@ class Button extends concordialang_ui_core_1.Widget { } renderToString() { // const inputType = this.getType(this.props.datatype as string) - const properties = prop_1.formatProperties( + const properties = utils_1.formatProperties( this.props, this.VALID_PROPERTIES ) diff --git a/dist/widgets/checkbox.js b/dist/widgets/checkbox.js index 89f082e..8212366 100644 --- a/dist/widgets/checkbox.js +++ b/dist/widgets/checkbox.js @@ -1,14 +1,15 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const prop_1 = require('./prop') +const utils_1 = require('../utils') class Checkbox extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name) this.VALID_PROPERTIES = ['value', 'required'] } + // TODO: remove \n renderToString() { - const properties = prop_1.formatProperties( + const properties = utils_1.formatProperties( this.props, this.VALID_PROPERTIES ) diff --git a/dist/widgets/index.d.ts b/dist/widgets/index.d.ts deleted file mode 100644 index 7fe5a18..0000000 --- a/dist/widgets/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './button'; -export * from './input'; -export * from './prop'; -export * from './widget-factory'; diff --git a/dist/widgets/index.js b/dist/widgets/index.js deleted file mode 100644 index 9dfb8f8..0000000 --- a/dist/widgets/index.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' -Object.defineProperty(exports, '__esModule', { value: true }) -const tslib_1 = require('tslib') -tslib_1.__exportStar(require('./button'), exports) -tslib_1.__exportStar(require('./input'), exports) -tslib_1.__exportStar(require('./prop'), exports) -tslib_1.__exportStar(require('./widget-factory'), exports) diff --git a/dist/widgets/input.d.ts b/dist/widgets/input.d.ts index ecb4c44..828e52f 100644 --- a/dist/widgets/input.d.ts +++ b/dist/widgets/input.d.ts @@ -1,8 +1,11 @@ import { Widget } from 'concordialang-ui-core'; +import { WidgetConfig } from '../interfaces/custom_config'; export declare class Input extends Widget { + private _customDefinition?; private readonly VALID_PROPERTIES; - constructor(props: any, name: string); + constructor(props: any, name: string, _customDefinition?: WidgetConfig | undefined); renderToString(): string; + private createInput; + private wrap; private getType; - private typeForDataType; } diff --git a/dist/widgets/input.js b/dist/widgets/input.js index 229a3a8..383f3ff 100644 --- a/dist/widgets/input.js +++ b/dist/widgets/input.js @@ -1,10 +1,13 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const prop_1 = require('./prop') +const lodash_1 = require('lodash') +const utils_1 = require('../utils') +const custom_config_1 = require('../interfaces/custom_config') class Input extends concordialang_ui_core_1.Widget { - constructor(props, name) { + constructor(props, name, _customDefinition) { super(props, name) + this._customDefinition = _customDefinition this.VALID_PROPERTIES = [ 'id', 'editable', @@ -15,32 +18,61 @@ class Input extends concordialang_ui_core_1.Widget { ] } renderToString() { + const input = this.createInput() + const label = utils_1.createLabel(this.name, this.props.id.toString()) + return this.wrap(label + input) + } + createInput() { const inputType = this.getType(this.props.datatype) - const properties = prop_1.formatProperties( + const inputOpening = lodash_1.get( + this._customDefinition, + custom_config_1.WIDGET_OPENING, + 'input' + ) + const inputClosure = lodash_1.get( + this._customDefinition, + custom_config_1.WIDGET_CLOSURE + ) + const properties = utils_1.formatProperties( this.props, this.VALID_PROPERTIES ) - const input = properties - ? `\n` - : `\n` - const label = prop_1.createLabel(this.name, this.props.id.toString()) - return `
\n${label + input}
` + if (inputClosure) { + return `<${inputOpening} ${inputType} ${properties}>` + } else { + return `<${inputOpening} ${inputType} ${properties}>` + } } - getType(datatype) { - const typeProperty = this.typeForDataType(datatype) - return `type="${typeProperty}"` + wrap(elements) { + const wrapperOpening = lodash_1.get( + this._customDefinition, + custom_config_1.WIDGET_WRAPPER_OPENING, + '
' + ) + const wrapperEnclosing = lodash_1.get( + this._customDefinition, + custom_config_1.WIDGET_WRAPPER_CLOSURE, + '
' + ) + return wrapperOpening + elements + wrapperEnclosing } - typeForDataType(datatype) { + getType(datatype) { + let typeProperty switch (datatype) { case 'integer' /* INTEGER */: case 'double' /* DOUBLE */: - return 'number' + typeProperty = 'number' + break case 'time' /* TIME */: - return 'time' + typeProperty = 'time' + break case 'datetime' /* DATETIME */: - return 'datetime-local' + typeProperty = 'datetime-local' + break + default: + typeProperty = 'text' } - return 'text' + return `type="${typeProperty}"` } } exports.Input = Input diff --git a/dist/widgets/radio.js b/dist/widgets/radio.js index 7ca33f8..38164a9 100644 --- a/dist/widgets/radio.js +++ b/dist/widgets/radio.js @@ -1,19 +1,20 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const prop_1 = require('./prop') +const utils_1 = require('../utils') class Radio extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name) this.VALID_PROPERTIES = ['value'] } + // TODO: remove \n renderToString() { - const properties = prop_1.formatProperties( + const properties = utils_1.formatProperties( this.props, this.VALID_PROPERTIES ) let inputs = [] - const label = prop_1.createLabel(this.name, this.props.id.toString()) + const label = utils_1.createLabel(this.name, this.props.id.toString()) const inputName = this.name.toLowerCase() if (properties) { for (let value of this.props.value) { diff --git a/dist/widgets/select.js b/dist/widgets/select.js index 0e6c0f1..8617dd0 100644 --- a/dist/widgets/select.js +++ b/dist/widgets/select.js @@ -1,21 +1,22 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const prop_1 = require('./prop') +const utils_1 = require('../utils') class Select extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name) this.VALID_PROPERTIES = ['id', 'required'] } + // TODO: remove \n renderToString() { - const properties = prop_1.formatProperties( + const properties = utils_1.formatProperties( this.props, this.VALID_PROPERTIES ) if (!properties) return '
\n\n
' const options = this.getOptions() const select = `\n` - const label = prop_1.createLabel(this.name, this.props.id.toString()) + const label = utils_1.createLabel(this.name, this.props.id.toString()) return `
\n${label + select}
` } getOptions() { diff --git a/dist/widgets/widget-factory.d.ts b/dist/widgets/widget-factory.d.ts index 18c5714..a100b76 100644 --- a/dist/widgets/widget-factory.d.ts +++ b/dist/widgets/widget-factory.d.ts @@ -1,4 +1,8 @@ import { UiElement, Widget } from 'concordialang-ui-core'; +import { ConfigLoader } from '../utils/config_loader'; export default class WidgetFactory { + private _configLoader; + constructor(_configLoader: ConfigLoader); create(element: UiElement): Widget; + private createInputElement; } diff --git a/dist/widgets/widget-factory.js b/dist/widgets/widget-factory.js index e261294..a045696 100644 --- a/dist/widgets/widget-factory.js +++ b/dist/widgets/widget-factory.js @@ -1,18 +1,41 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const button_1 = require('./button') +const input_1 = require('./input') +const checkbox_1 = require('./checkbox') +const radio_1 = require('./radio') +const select_1 = require('./select') class WidgetFactory { + // criar uma classe "ConfigLoader" que recebe "config" no construtor + // criar uma interface para "config" + constructor(_configLoader) { + this._configLoader = _configLoader + } create(element) { switch (element.widget) { - //case Widgets.TEXTBOX: return new Input(element.props, element.name) + case 'textbox' /* TEXTBOX */: + return this.createInputElement(element) case 'button' /* BUTTON */: return new button_1.Button(element.props, element.name) - //case Widgets.CHECKBOX: return new Checkbox(element.props, element.name) - //case Widgets.RADIO: return new Radio(element.props, element.name) - //case Widgets.SELECT: return new Select(element.props, element.name) + case 'checkbox' /* CHECKBOX */: + return new checkbox_1.Checkbox(element.props, element.name) + case 'radio' /* RADIO */: + return new radio_1.Radio(element.props, element.name) + case 'select' /* SELECT */: + return new select_1.Select(element.props, element.name) default: throw new Error(`Invalid widget type: ${element.widget}`) } } + createInputElement(element) { + const customInputDefinition = this._configLoader.getInputDefinition() + if (customInputDefinition) + return new input_1.Input( + element.props, + element.name, + customInputDefinition + ) + return new input_1.Input(element.props, element.name) + } } exports.default = WidgetFactory diff --git a/package-lock.json b/package-lock.json index ac1c4d0..54fcb5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -813,6 +813,11 @@ "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", "dev": true }, + "@types/lodash": { + "version": "4.14.134", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.134.tgz", + "integrity": "sha512-2/O0khFUCFeDlbi7sZ7ZFRCcT812fAeOLm7Ev4KbwASkZ575TDrDcY7YyaoHdTOzKcNbfiwLYZqPmoC4wadrsw==" + }, "@types/node": { "version": "10.14.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.4.tgz", @@ -860,11 +865,6 @@ "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", "dev": true }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", @@ -967,7 +967,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -1255,7 +1254,8 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", @@ -1335,6 +1335,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1471,7 +1472,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, "requires": { "callsites": "^2.0.0" }, @@ -1479,8 +1479,7 @@ "callsites": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" } } }, @@ -1488,7 +1487,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, "requires": { "caller-callsite": "^2.0.0" } @@ -1854,7 +1852,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concordialang-ui-core": { "version": "0.2.2", @@ -1865,43 +1864,6 @@ "database-js-json": "^1.2.1" } }, - "condense-newlines": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz", - "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=", - "requires": { - "extend-shallow": "^2.0.1", - "is-whitespace": "^0.3.0", - "kind-of": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -1930,14 +1892,13 @@ "dev": true }, "cosmiconfig": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz", - "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==", - "dev": true, + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "requires": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", - "js-yaml": "^3.13.0", + "js-yaml": "^3.13.1", "parse-json": "^4.0.0" } }, @@ -2226,24 +2187,6 @@ "safer-buffer": "^2.1.0" } }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" - } - } - }, "elegant-spinner": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", @@ -2269,7 +2212,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -2341,8 +2283,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "estraverse": { "version": "4.2.0", @@ -2719,7 +2660,8 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "1.2.7", @@ -3346,6 +3288,7 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3746,7 +3689,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, "requires": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" @@ -3831,6 +3773,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -3839,12 +3782,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "invariant": { "version": "2.2.4", @@ -3890,13 +3829,13 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, "is-callable": { "version": "1.1.4", @@ -3961,13 +3900,13 @@ "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true }, "is-extglob": { "version": "2.1.1", @@ -4117,11 +4056,6 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "is-whitespace": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz", - "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=" - }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -4748,18 +4682,6 @@ "resolved": "https://registry.npmjs.org/jl-sql-api/-/jl-sql-api-2.8.1.tgz", "integrity": "sha1-BbB9JdxxhxcZwG/CFuS4lsZ4gUc=" }, - "js-beautify": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.9.1.tgz", - "integrity": "sha512-oxxvVZdOdUfzk8IOLBF2XUZvl2GoBEfA+b0of4u2EBY/46NlXasi8JdFvazA5lCrf9/lQhTjyVy2QCUW7iq0MQ==", - "requires": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.2", - "glob": "^7.1.3", - "mkdirp": "~0.5.0", - "nopt": "~4.0.1" - } - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4770,7 +4692,6 @@ "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -4825,8 +4746,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { "version": "0.2.3", @@ -5159,8 +5079,7 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -5255,15 +5174,6 @@ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", "dev": true }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", @@ -5403,6 +5313,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5410,7 +5321,8 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mixin-deep": { "version": "1.3.1", @@ -5437,6 +5349,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -5530,15 +5443,6 @@ "which": "^1.3.0" } }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -5682,6 +5586,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -5735,11 +5640,6 @@ } } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -5790,16 +5690,8 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "p-defer": { "version": "1.0.0", @@ -5877,7 +5769,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -5920,7 +5811,8 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-is-inside": { "version": "1.0.2", @@ -6027,26 +5919,6 @@ "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==", "dev": true }, - "pretty": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz", - "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=", - "requires": { - "condense-newlines": "^0.2.1", - "extend-shallow": "^2.0.1", - "js-beautify": "^1.6.12" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "pretty-format": { "version": "24.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.7.0.tgz", @@ -6081,16 +5953,6 @@ "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", "dev": true }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, "psl": { "version": "1.1.31", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", @@ -6426,8 +6288,7 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, "resolve-url": { "version": "0.2.1", @@ -6628,11 +6489,6 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", "dev": true }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -6884,8 +6740,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { "version": "1.16.1", @@ -7718,7 +7573,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write-file-atomic": { "version": "2.4.2", @@ -7772,11 +7628,6 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, "yargs": { "version": "12.0.5", "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", diff --git a/package.json b/package.json index 4214247..eb4d77c 100644 --- a/package.json +++ b/package.json @@ -72,8 +72,10 @@ "dependencies": { "@oclif/command": "^1.5.12", "@oclif/config": "^1.12.12", + "@types/lodash": "^4.14.134", "concordialang-ui-core": "^0.2.2", - "pretty": "^2.0.0", + "cosmiconfig": "^5.2.1", + "lodash": "^4.17.11", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/src/generator.ts b/src/generator.ts index 075c50b..5287802 100644 --- a/src/generator.ts +++ b/src/generator.ts @@ -2,16 +2,25 @@ import { Feature, Prototyper, Widget } from 'concordialang-ui-core' import * as fs from 'fs' import { promisify } from 'util' import { format } from 'path' -const pretty = require('pretty') +const prettier = require('prettier') +const cosmiconfig = require('cosmiconfig') import WidgetFactory from './widgets/widget-factory' +// TODO: use "export default" +import { ConfigLoader } from './utils/config_loader' export default class Generator implements Prototyper { constructor(private _fs: any = fs, private _outputDir: string) { } public async generate(features: Feature[]): Promise { - const factory = new WidgetFactory() + // search for a ".configrc.json" + // TODO: replace "config" with the CLI name + const explorer = cosmiconfig('config') + let config = explorer.searchSync() + + const configLoader = new ConfigLoader(config) + const factory = new WidgetFactory(configLoader) let createFilePromises: Promise[] = [] for (let feature of features) { @@ -24,10 +33,10 @@ export default class Generator implements Prototyper { private async createHtmlFile(fileName: string, widgets: Widget[]): Promise { let content = widgets.reduce((result, widget) => { - return result + widget.renderToString() + '\n' + return result + widget.renderToString() }, '') - content = pretty(`
\n${content}
`, {ocd: true}) + content = prettier.format(`
\n${content}
`, {parser: 'html', htmlWhitespaceSensitivity: 'ignore'}) const path = format({ dir: this._outputDir, name: fileName, ext: '.html' }) await promisify(fs.writeFile)(path, content) diff --git a/src/interfaces/custom_config.ts b/src/interfaces/custom_config.ts new file mode 100644 index 0000000..390858e --- /dev/null +++ b/src/interfaces/custom_config.ts @@ -0,0 +1,18 @@ +export interface CustomConfig { + widgets?: { + input?: WidgetConfig + } +} + +export interface WidgetConfig { + opening: string, + closure?: string, + header?: string, + footer?: string +} + +// path for properties in WidgetConfig to by used in lodash "get" method +export const WIDGET_OPENING = 'opening' +export const WIDGET_CLOSURE = 'closure' +export const WIDGET_WRAPPER_OPENING = 'header' +export const WIDGET_WRAPPER_CLOSURE = 'footer' diff --git a/src/utils/config_loader.ts b/src/utils/config_loader.ts new file mode 100644 index 0000000..31872d3 --- /dev/null +++ b/src/utils/config_loader.ts @@ -0,0 +1,10 @@ +import { get } from 'lodash'; +import { CustomConfig, WidgetConfig } from '../interfaces/custom_config'; + +export class ConfigLoader { + constructor(private _config: CustomConfig) {} + + public getInputDefinition(): WidgetConfig { + return get(this._config, 'config.widgets.input') + } +} diff --git a/src/utils/create_label.ts b/src/utils/create_label.ts new file mode 100644 index 0000000..51f1061 --- /dev/null +++ b/src/utils/create_label.ts @@ -0,0 +1,5 @@ +export function createLabel(name: string, id: string): string { + const validIdPattern = /^(#|~|\d|\w).*/ + const labelFor = (validIdPattern.test(id)) ? `for="${id.replace(/^#|~/ , '')}"` : '' + return `` +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..b3430ae --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,2 @@ +export * from './prop' +export * from './create_label' diff --git a/src/widgets/prop.ts b/src/utils/prop.ts similarity index 83% rename from src/widgets/prop.ts rename to src/utils/prop.ts index 0af134d..5741272 100644 --- a/src/widgets/prop.ts +++ b/src/utils/prop.ts @@ -12,10 +12,11 @@ export function formatProperties(props: any, validProperties: string[]): string if(key === 'id') { let newKey = key + // TODO: replace test wit str.match(pattern) if(!invalidIdPattern.test(value)) { const validIdPattern = /^#|~/ const validClassPattern = /^\./ - + if(validIdPattern.test(value)) { value = value.toString().replace(validIdPattern, '') } else if(validClassPattern.test(value)) { @@ -24,10 +25,8 @@ export function formatProperties(props: any, validProperties: string[]): string } return `${translateProp(newKey)}="${value}"` } - } - return `${translateProp(key)}="${value}"` } @@ -39,11 +38,3 @@ export function formatProperties(props: any, validProperties: string[]): string return Object.keys(props).reduce(formatValid, '').trimRight() } - -export function createLabel(name: string, id: string): string { - - const validIdPattern = /^(#|~|\d|\w).*/ - - const labelFor = (validIdPattern.test(id)) ? `for="${id.replace(/^#|~/ , '')}"` : '' - return `\n` -} \ No newline at end of file diff --git a/src/widgets/button.ts b/src/widgets/button.ts index c00691a..a4d8d8b 100644 --- a/src/widgets/button.ts +++ b/src/widgets/button.ts @@ -1,6 +1,6 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties} from './prop' +import {formatProperties} from '../utils' export class Button extends Widget { private readonly VALID_PROPERTIES = ['id', 'disabled', 'value'] diff --git a/src/widgets/checkbox.ts b/src/widgets/checkbox.ts index 1007fa1..d4866cd 100644 --- a/src/widgets/checkbox.ts +++ b/src/widgets/checkbox.ts @@ -1,6 +1,6 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties} from './prop' +import {formatProperties} from '../utils' export class Checkbox extends Widget { private readonly VALID_PROPERTIES = ['value', 'required'] @@ -9,6 +9,7 @@ export class Checkbox extends Widget { super(props, name) } + // TODO: remove \n public renderToString(): string { const properties = formatProperties(this.props, this.VALID_PROPERTIES) if (properties) return `
\n${this.name}\n
` diff --git a/src/widgets/index.ts b/src/widgets/index.ts deleted file mode 100644 index 7fe5a18..0000000 --- a/src/widgets/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './button'; -export * from './input'; -export * from './prop'; -export * from './widget-factory'; diff --git a/src/widgets/input.ts b/src/widgets/input.ts index 87953a5..d855949 100644 --- a/src/widgets/input.ts +++ b/src/widgets/input.ts @@ -1,6 +1,14 @@ -import {Widget} from 'concordialang-ui-core' +import { Widget } from 'concordialang-ui-core' +import { get } from 'lodash'; -import {formatProperties, createLabel} from './prop' +import { formatProperties, createLabel } from '../utils' +import { + WidgetConfig, + WIDGET_OPENING, + WIDGET_CLOSURE, + WIDGET_WRAPPER_OPENING, + WIDGET_WRAPPER_CLOSURE +} from '../interfaces/custom_config' const enum DataTypes { STRING = 'string', @@ -14,30 +22,46 @@ const enum DataTypes { export class Input extends Widget { private readonly VALID_PROPERTIES = ['id', 'editable', 'minlength', 'maxlength', 'required', 'format'] - constructor(props: any, name: string) { + constructor(props: any, name: string, private _customDefinition?: WidgetConfig) { super(props, name) } public renderToString(): string { + const input = this.createInput() + const label = createLabel(this.name, this.props.id.toString()) + return this.wrap(label + input) + } + + private createInput(): string { const inputType = this.getType(this.props.datatype as string) + const inputOpening = get(this._customDefinition, WIDGET_OPENING, 'input') + const inputClosure = get(this._customDefinition, WIDGET_CLOSURE) const properties = formatProperties(this.props, this.VALID_PROPERTIES) - const input = properties ? `\n` : `\n` - const label = createLabel(this.name, this.props.id.toString()) - return `
\n${label + input}
` + + if (inputClosure) { + return `<${inputOpening} ${inputType} ${properties}>` + } else { + return `<${inputOpening} ${inputType} ${properties}>` + } } - private getType(datatype: string): string { - const typeProperty = this.typeForDataType(datatype) - return `type="${typeProperty}"` + private wrap(elements: string): string { + const wrapperOpening = get(this._customDefinition, WIDGET_WRAPPER_OPENING, '
') + const wrapperEnclosing = get(this._customDefinition, WIDGET_WRAPPER_CLOSURE, '
') + return wrapperOpening + elements + wrapperEnclosing } - private typeForDataType(datatype: string): string { + private getType(datatype: string): string { + let typeProperty + switch (datatype) { case DataTypes.INTEGER: - case DataTypes.DOUBLE: return 'number' - case DataTypes.TIME: return 'time' - case DataTypes.DATETIME: return 'datetime-local' + case DataTypes.DOUBLE: typeProperty = 'number'; break + case DataTypes.TIME: typeProperty = 'time'; break + case DataTypes.DATETIME: typeProperty = 'datetime-local'; break + default: typeProperty = 'text' } - return 'text' + + return `type="${typeProperty}"` } } diff --git a/src/widgets/radio.ts b/src/widgets/radio.ts index 73b2117..3cebafd 100644 --- a/src/widgets/radio.ts +++ b/src/widgets/radio.ts @@ -1,6 +1,6 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties, createLabel} from './prop' +import {formatProperties, createLabel} from '../utils' export class Radio extends Widget { private readonly VALID_PROPERTIES = ['value'] @@ -9,6 +9,7 @@ export class Radio extends Widget { super(props, name) } + // TODO: remove \n public renderToString(): string { const properties = formatProperties(this.props, this.VALID_PROPERTIES) let inputs: String[] = [] diff --git a/src/widgets/select.ts b/src/widgets/select.ts index 18ab9a9..d15f47d 100644 --- a/src/widgets/select.ts +++ b/src/widgets/select.ts @@ -1,6 +1,6 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties, createLabel} from './prop' +import {formatProperties, createLabel} from '../utils' export class Select extends Widget { private readonly VALID_PROPERTIES = ['id', 'required'] @@ -9,6 +9,7 @@ export class Select extends Widget { super(props, name) } + // TODO: remove \n public renderToString(): string { const properties = formatProperties(this.props, this.VALID_PROPERTIES) if (!properties) return '
\n\n
' diff --git a/src/widgets/widget-factory.ts b/src/widgets/widget-factory.ts index c7954ef..43809af 100644 --- a/src/widgets/widget-factory.ts +++ b/src/widgets/widget-factory.ts @@ -5,6 +5,7 @@ import {Input} from './input' import {Checkbox} from './checkbox' import {Radio} from './radio' import {Select} from './select' +import {ConfigLoader} from '../utils/config_loader' const enum Widgets { BUTTON = 'button', @@ -15,9 +16,13 @@ const enum Widgets { } export default class WidgetFactory { + // criar uma classe "ConfigLoader" que recebe "config" no construtor + // criar uma interface para "config" + constructor(private _configLoader: ConfigLoader) {} + create(element: UiElement): Widget { switch (element.widget) { - case Widgets.TEXTBOX: return new Input(element.props, element.name) + case Widgets.TEXTBOX: return this.createInputElement(element) case Widgets.BUTTON: return new Button(element.props, element.name) case Widgets.CHECKBOX: return new Checkbox(element.props, element.name) case Widgets.RADIO: return new Radio(element.props, element.name) @@ -25,4 +30,10 @@ export default class WidgetFactory { default: throw new Error(`Invalid widget type: ${element.widget}`) } } + + private createInputElement(element: UiElement): any { + const customInputDefinition = this._configLoader.getInputDefinition() + if (customInputDefinition) return new Input(element.props, element.name, customInputDefinition) + return new Input(element.props, element.name) + } } From 1941d23979243b9fe6836bbdb04a0078dfc0de0b Mon Sep 17 00:00:00 2001 From: Willian Date: Mon, 17 Jun 2019 22:54:44 -0300 Subject: [PATCH 04/12] Fix file names, exports and refactor input element generation --- dist/commands/generate.js | 7 ++- ...generator.d.ts => html-ui-prototyper.d.ts} | 2 +- dist/{generator.js => html-ui-prototyper.js} | 11 ++-- dist/index.d.ts | 2 +- dist/index.js | 2 +- dist/interfaces/app-config.d.ts | 11 ++++ dist/interfaces/app-config.js | 2 + dist/interfaces/custom_config.d.ts | 15 ------ dist/interfaces/custom_config.js | 7 --- dist/utils/config_loader.d.ts | 6 --- dist/utils/config_loader.js | 12 ----- .../{create_label.d.ts => create-label.d.ts} | 0 .../{create_label.js => create-label.js} | 0 dist/utils/index.d.ts | 2 +- dist/utils/index.js | 2 +- dist/widgets/button.d.ts | 2 +- dist/widgets/button.js | 2 +- dist/widgets/checkbox.d.ts | 2 +- dist/widgets/checkbox.js | 2 +- dist/widgets/input.d.ts | 9 ++-- dist/widgets/input.js | 50 ++++++------------- dist/widgets/radio.d.ts | 2 +- dist/widgets/radio.js | 2 +- dist/widgets/select.d.ts | 2 +- dist/widgets/select.js | 2 +- dist/widgets/widget-factory.d.ts | 6 +-- dist/widgets/widget-factory.js | 25 ++++------ package-lock.json | 6 +-- package.json | 2 +- src/commands/generate.ts | 4 +- src/{generator.ts => html-ui-prototyper.ts} | 9 ++-- src/index.ts | 2 +- src/interfaces/app-config.ts | 12 +++++ src/interfaces/custom_config.ts | 18 ------- src/utils/config_loader.ts | 10 ---- .../{create_label.ts => create-label.ts} | 0 src/utils/index.ts | 2 +- src/widgets/button.ts | 2 +- src/widgets/checkbox.ts | 2 +- src/widgets/input.ts | 35 ++++--------- src/widgets/radio.ts | 2 +- src/widgets/select.ts | 2 +- src/widgets/widget-factory.ts | 22 ++++---- 43 files changed, 114 insertions(+), 203 deletions(-) rename dist/{generator.d.ts => html-ui-prototyper.d.ts} (78%) rename dist/{generator.js => html-ui-prototyper.js} (85%) create mode 100644 dist/interfaces/app-config.d.ts create mode 100644 dist/interfaces/app-config.js delete mode 100644 dist/interfaces/custom_config.d.ts delete mode 100644 dist/interfaces/custom_config.js delete mode 100644 dist/utils/config_loader.d.ts delete mode 100644 dist/utils/config_loader.js rename dist/utils/{create_label.d.ts => create-label.d.ts} (100%) rename dist/utils/{create_label.js => create-label.js} (100%) rename src/{generator.ts => html-ui-prototyper.ts} (84%) create mode 100644 src/interfaces/app-config.ts delete mode 100644 src/interfaces/custom_config.ts delete mode 100644 src/utils/config_loader.ts rename src/utils/{create_label.ts => create-label.ts} (100%) diff --git a/dist/commands/generate.js b/dist/commands/generate.js index 9724772..93cad7e 100644 --- a/dist/commands/generate.js +++ b/dist/commands/generate.js @@ -3,14 +3,17 @@ Object.defineProperty(exports, '__esModule', { value: true }) const tslib_1 = require('tslib') const command_1 = require('@oclif/command') const fs = require('fs') -const generator_1 = require('../generator') +const html_ui_prototyper_1 = require('../html-ui-prototyper') class Generate extends command_1.Command { run() { return tslib_1.__awaiter(this, void 0, void 0, function*() { const { flags } = this.parse(Generate) if (flags.features) { const processResult = JSON.parse(flags.features) - const generator = new generator_1.default(fs, flags.outputDir) + const generator = new html_ui_prototyper_1.default( + fs, + flags.outputDir + ) const result = yield generator.generate(processResult.features) this.log(JSON.stringify(result)) } diff --git a/dist/generator.d.ts b/dist/html-ui-prototyper.d.ts similarity index 78% rename from dist/generator.d.ts rename to dist/html-ui-prototyper.d.ts index e76df41..a685f12 100644 --- a/dist/generator.d.ts +++ b/dist/html-ui-prototyper.d.ts @@ -1,5 +1,5 @@ import { Feature, Prototyper } from 'concordialang-ui-core'; -export default class Generator implements Prototyper { +export default class HtmlUIPrototyper implements Prototyper { private _fs; private _outputDir; constructor(_fs: any, _outputDir: string); diff --git a/dist/generator.js b/dist/html-ui-prototyper.js similarity index 85% rename from dist/generator.js rename to dist/html-ui-prototyper.js index cfe5eac..0bec5f7 100644 --- a/dist/generator.js +++ b/dist/html-ui-prototyper.js @@ -7,9 +7,7 @@ const path_1 = require('path') const prettier = require('prettier') const cosmiconfig = require('cosmiconfig') const widget_factory_1 = require('./widgets/widget-factory') -// TODO: use "export default" -const config_loader_1 = require('./utils/config_loader') -class Generator { +class HtmlUIPrototyper { constructor(_fs = fs, _outputDir) { this._fs = _fs this._outputDir = _outputDir @@ -20,8 +18,9 @@ class Generator { // TODO: replace "config" with the CLI name const explorer = cosmiconfig('config') let config = explorer.searchSync() - const configLoader = new config_loader_1.ConfigLoader(config) - const factory = new widget_factory_1.default(configLoader) + // TODO: lançar exceção se arquivo não existir + // TODO: extrair "config" de config + const factory = new widget_factory_1.default(config.config) let createFilePromises = [] for (let feature of features) { const elements = feature.uiElements.map(uiElement => @@ -53,4 +52,4 @@ class Generator { }) } } -exports.default = Generator +exports.default = HtmlUIPrototyper diff --git a/dist/index.d.ts b/dist/index.d.ts index 95bc5ff..48bbdaa 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1 +1 @@ -export * from './generator'; +export * from './html-ui-prototyper'; diff --git a/dist/index.js b/dist/index.js index efdaceb..33bdeb0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,4 +1,4 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const tslib_1 = require('tslib') -tslib_1.__exportStar(require('./generator'), exports) +tslib_1.__exportStar(require('./html-ui-prototyper'), exports) diff --git a/dist/interfaces/app-config.d.ts b/dist/interfaces/app-config.d.ts new file mode 100644 index 0000000..d56546e --- /dev/null +++ b/dist/interfaces/app-config.d.ts @@ -0,0 +1,11 @@ +export interface AppConfig { + widgets?: { + input?: WidgetConfig; + }; +} +export interface WidgetConfig { + opening: string; + closure?: string; + wrapperOpening?: string; + wrapperClosure?: string; +} diff --git a/dist/interfaces/app-config.js b/dist/interfaces/app-config.js new file mode 100644 index 0000000..0a483a3 --- /dev/null +++ b/dist/interfaces/app-config.js @@ -0,0 +1,2 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) diff --git a/dist/interfaces/custom_config.d.ts b/dist/interfaces/custom_config.d.ts deleted file mode 100644 index bdcbf22..0000000 --- a/dist/interfaces/custom_config.d.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface CustomConfig { - widgets?: { - input?: WidgetConfig; - }; -} -export interface WidgetConfig { - opening: string; - closure?: string; - header?: string; - footer?: string; -} -export declare const WIDGET_OPENING = "opening"; -export declare const WIDGET_CLOSURE = "closure"; -export declare const WIDGET_WRAPPER_OPENING = "header"; -export declare const WIDGET_WRAPPER_CLOSURE = "footer"; diff --git a/dist/interfaces/custom_config.js b/dist/interfaces/custom_config.js deleted file mode 100644 index e6dd1cb..0000000 --- a/dist/interfaces/custom_config.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict' -Object.defineProperty(exports, '__esModule', { value: true }) -// path for properties in WidgetConfig to by used in lodash "get" method -exports.WIDGET_OPENING = 'opening' -exports.WIDGET_CLOSURE = 'closure' -exports.WIDGET_WRAPPER_OPENING = 'header' -exports.WIDGET_WRAPPER_CLOSURE = 'footer' diff --git a/dist/utils/config_loader.d.ts b/dist/utils/config_loader.d.ts deleted file mode 100644 index 24fa186..0000000 --- a/dist/utils/config_loader.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CustomConfig, WidgetConfig } from '../interfaces/custom_config'; -export declare class ConfigLoader { - private _config; - constructor(_config: CustomConfig); - getInputDefinition(): WidgetConfig; -} diff --git a/dist/utils/config_loader.js b/dist/utils/config_loader.js deleted file mode 100644 index 6fdcea5..0000000 --- a/dist/utils/config_loader.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' -Object.defineProperty(exports, '__esModule', { value: true }) -const lodash_1 = require('lodash') -class ConfigLoader { - constructor(_config) { - this._config = _config - } - getInputDefinition() { - return lodash_1.get(this._config, 'config.widgets.input') - } -} -exports.ConfigLoader = ConfigLoader diff --git a/dist/utils/create_label.d.ts b/dist/utils/create-label.d.ts similarity index 100% rename from dist/utils/create_label.d.ts rename to dist/utils/create-label.d.ts diff --git a/dist/utils/create_label.js b/dist/utils/create-label.js similarity index 100% rename from dist/utils/create_label.js rename to dist/utils/create-label.js diff --git a/dist/utils/index.d.ts b/dist/utils/index.d.ts index f812114..a263ba0 100644 --- a/dist/utils/index.d.ts +++ b/dist/utils/index.d.ts @@ -1,2 +1,2 @@ export * from './prop'; -export * from './create_label'; +export * from './create-label'; diff --git a/dist/utils/index.js b/dist/utils/index.js index dfd1a2f..bc6c1c1 100644 --- a/dist/utils/index.js +++ b/dist/utils/index.js @@ -2,4 +2,4 @@ Object.defineProperty(exports, '__esModule', { value: true }) const tslib_1 = require('tslib') tslib_1.__exportStar(require('./prop'), exports) -tslib_1.__exportStar(require('./create_label'), exports) +tslib_1.__exportStar(require('./create-label'), exports) diff --git a/dist/widgets/button.d.ts b/dist/widgets/button.d.ts index 5f9e996..906d5f2 100644 --- a/dist/widgets/button.d.ts +++ b/dist/widgets/button.d.ts @@ -1,5 +1,5 @@ import { Widget } from 'concordialang-ui-core'; -export declare class Button extends Widget { +export default class Button extends Widget { private readonly VALID_PROPERTIES; constructor(props: any, name?: string); renderToString(): string; diff --git a/dist/widgets/button.js b/dist/widgets/button.js index f40176d..85da2e0 100644 --- a/dist/widgets/button.js +++ b/dist/widgets/button.js @@ -20,4 +20,4 @@ class Button extends concordialang_ui_core_1.Widget { return `type="${datatype || 'button'}"` } } -exports.Button = Button +exports.default = Button diff --git a/dist/widgets/checkbox.d.ts b/dist/widgets/checkbox.d.ts index 85c1f79..b7204c6 100644 --- a/dist/widgets/checkbox.d.ts +++ b/dist/widgets/checkbox.d.ts @@ -1,5 +1,5 @@ import { Widget } from 'concordialang-ui-core'; -export declare class Checkbox extends Widget { +export default class Checkbox extends Widget { private readonly VALID_PROPERTIES; constructor(props: any, name: string); renderToString(): string; diff --git a/dist/widgets/checkbox.js b/dist/widgets/checkbox.js index 8212366..7a1acab 100644 --- a/dist/widgets/checkbox.js +++ b/dist/widgets/checkbox.js @@ -20,4 +20,4 @@ class Checkbox extends concordialang_ui_core_1.Widget { return `
\n${this.name}\n
` } } -exports.Checkbox = Checkbox +exports.default = Checkbox diff --git a/dist/widgets/input.d.ts b/dist/widgets/input.d.ts index 828e52f..eb72d3a 100644 --- a/dist/widgets/input.d.ts +++ b/dist/widgets/input.d.ts @@ -1,11 +1,10 @@ import { Widget } from 'concordialang-ui-core'; -import { WidgetConfig } from '../interfaces/custom_config'; -export declare class Input extends Widget { - private _customDefinition?; +import { WidgetConfig } from '../interfaces/app-config'; +export default class Input extends Widget { + private _config; private readonly VALID_PROPERTIES; - constructor(props: any, name: string, _customDefinition?: WidgetConfig | undefined); + constructor(props: any, name: string, _config: WidgetConfig); renderToString(): string; - private createInput; private wrap; private getType; } diff --git a/dist/widgets/input.js b/dist/widgets/input.js index 383f3ff..b91c413 100644 --- a/dist/widgets/input.js +++ b/dist/widgets/input.js @@ -1,13 +1,11 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const lodash_1 = require('lodash') const utils_1 = require('../utils') -const custom_config_1 = require('../interfaces/custom_config') class Input extends concordialang_ui_core_1.Widget { - constructor(props, name, _customDefinition) { + constructor(props, name, _config) { super(props, name) - this._customDefinition = _customDefinition + this._config = _config this.VALID_PROPERTIES = [ 'id', 'editable', @@ -18,43 +16,25 @@ class Input extends concordialang_ui_core_1.Widget { ] } renderToString() { - const input = this.createInput() - const label = utils_1.createLabel(this.name, this.props.id.toString()) - return this.wrap(label + input) - } - createInput() { const inputType = this.getType(this.props.datatype) - const inputOpening = lodash_1.get( - this._customDefinition, - custom_config_1.WIDGET_OPENING, - 'input' - ) - const inputClosure = lodash_1.get( - this._customDefinition, - custom_config_1.WIDGET_CLOSURE - ) const properties = utils_1.formatProperties( this.props, this.VALID_PROPERTIES ) - if (inputClosure) { - return `<${inputOpening} ${inputType} ${properties}>` - } else { - return `<${inputOpening} ${inputType} ${properties}>` - } + const input = + this._config.opening.replace('%s', `${inputType} ${properties}`) + + this._config.closure + const label = utils_1.createLabel(this.name, this.props.id.toString()) + return this.wrap(label + input) } wrap(elements) { - const wrapperOpening = lodash_1.get( - this._customDefinition, - custom_config_1.WIDGET_WRAPPER_OPENING, - '
' - ) - const wrapperEnclosing = lodash_1.get( - this._customDefinition, - custom_config_1.WIDGET_WRAPPER_CLOSURE, - '
' - ) - return wrapperOpening + elements + wrapperEnclosing + if (this._config.wrapperOpening && this._config.wrapperClosure) + return ( + this._config.wrapperOpening + + elements + + this._config.wrapperClosure + ) + return elements } getType(datatype) { let typeProperty @@ -75,4 +55,4 @@ class Input extends concordialang_ui_core_1.Widget { return `type="${typeProperty}"` } } -exports.Input = Input +exports.default = Input diff --git a/dist/widgets/radio.d.ts b/dist/widgets/radio.d.ts index 28483b5..594884f 100644 --- a/dist/widgets/radio.d.ts +++ b/dist/widgets/radio.d.ts @@ -1,5 +1,5 @@ import { Widget } from 'concordialang-ui-core'; -export declare class Radio extends Widget { +export default class Radio extends Widget { private readonly VALID_PROPERTIES; constructor(props: any, name: string); renderToString(): string; diff --git a/dist/widgets/radio.js b/dist/widgets/radio.js index 38164a9..0149439 100644 --- a/dist/widgets/radio.js +++ b/dist/widgets/radio.js @@ -26,4 +26,4 @@ class Radio extends concordialang_ui_core_1.Widget { return '
\n\n
' } } -exports.Radio = Radio +exports.default = Radio diff --git a/dist/widgets/select.d.ts b/dist/widgets/select.d.ts index 31b574c..463e827 100644 --- a/dist/widgets/select.d.ts +++ b/dist/widgets/select.d.ts @@ -1,5 +1,5 @@ import { Widget } from 'concordialang-ui-core'; -export declare class Select extends Widget { +export default class Select extends Widget { private readonly VALID_PROPERTIES; constructor(props: any, name: string); renderToString(): string; diff --git a/dist/widgets/select.js b/dist/widgets/select.js index 8617dd0..5ba0e6b 100644 --- a/dist/widgets/select.js +++ b/dist/widgets/select.js @@ -28,4 +28,4 @@ class Select extends concordialang_ui_core_1.Widget { return options.join('\n') } } -exports.Select = Select +exports.default = Select diff --git a/dist/widgets/widget-factory.d.ts b/dist/widgets/widget-factory.d.ts index a100b76..5cd426e 100644 --- a/dist/widgets/widget-factory.d.ts +++ b/dist/widgets/widget-factory.d.ts @@ -1,8 +1,8 @@ import { UiElement, Widget } from 'concordialang-ui-core'; -import { ConfigLoader } from '../utils/config_loader'; +import { AppConfig } from '../interfaces/app-config'; export default class WidgetFactory { - private _configLoader; - constructor(_configLoader: ConfigLoader); + private _config; + constructor(_config: AppConfig); create(element: UiElement): Widget; private createInputElement; } diff --git a/dist/widgets/widget-factory.js b/dist/widgets/widget-factory.js index a045696..f188a64 100644 --- a/dist/widgets/widget-factory.js +++ b/dist/widgets/widget-factory.js @@ -1,41 +1,34 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) +const lodash_1 = require('lodash') const button_1 = require('./button') const input_1 = require('./input') const checkbox_1 = require('./checkbox') const radio_1 = require('./radio') const select_1 = require('./select') class WidgetFactory { - // criar uma classe "ConfigLoader" que recebe "config" no construtor - // criar uma interface para "config" - constructor(_configLoader) { - this._configLoader = _configLoader + constructor(_config) { + this._config = _config } create(element) { switch (element.widget) { case 'textbox' /* TEXTBOX */: return this.createInputElement(element) case 'button' /* BUTTON */: - return new button_1.Button(element.props, element.name) + return new button_1.default(element.props, element.name) case 'checkbox' /* CHECKBOX */: - return new checkbox_1.Checkbox(element.props, element.name) + return new checkbox_1.default(element.props, element.name) case 'radio' /* RADIO */: - return new radio_1.Radio(element.props, element.name) + return new radio_1.default(element.props, element.name) case 'select' /* SELECT */: - return new select_1.Select(element.props, element.name) + return new select_1.default(element.props, element.name) default: throw new Error(`Invalid widget type: ${element.widget}`) } } createInputElement(element) { - const customInputDefinition = this._configLoader.getInputDefinition() - if (customInputDefinition) - return new input_1.Input( - element.props, - element.name, - customInputDefinition - ) - return new input_1.Input(element.props, element.name) + const widgetConfig = lodash_1.get(this._config, 'widgets.input') + return new input_1.default(element.props, element.name, widgetConfig) } } exports.default = WidgetFactory diff --git a/package-lock.json b/package-lock.json index 54fcb5e..b71ba09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1856,9 +1856,9 @@ "dev": true }, "concordialang-ui-core": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/concordialang-ui-core/-/concordialang-ui-core-0.2.2.tgz", - "integrity": "sha512-1EONXdRmNQLPzVHxuMKGiY2dLejTbPJA3SiLhEKqqJNWMWle+MGsYGTMnsxFIxh7w+YTOifkuxg8DS6RjmfDVg==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/concordialang-ui-core/-/concordialang-ui-core-0.2.3.tgz", + "integrity": "sha512-F++5OA0XzPOEO5p2kgiJUvmvncR56x+fWuZSoVKm+Fdt8w6yJwJ31ivCKqYrM6MPrQxE9nG816fzy4V1IiDeEw==", "requires": { "database-js": "^3.0.8", "database-js-json": "^1.2.1" diff --git a/package.json b/package.json index eb4d77c..1b193f6 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "@oclif/command": "^1.5.12", "@oclif/config": "^1.12.12", "@types/lodash": "^4.14.134", - "concordialang-ui-core": "^0.2.2", + "concordialang-ui-core": "^0.2.3", "cosmiconfig": "^5.2.1", "lodash": "^4.17.11", "tslib": "^1.9.3" diff --git a/src/commands/generate.ts b/src/commands/generate.ts index 374d41a..1f59803 100644 --- a/src/commands/generate.ts +++ b/src/commands/generate.ts @@ -2,7 +2,7 @@ import {Command, flags} from '@oclif/command' import {ProcessResult} from 'concordialang-ui-core' import * as fs from 'fs' -import Generator from '../generator' +import HtmlUIPrototyper from '../html-ui-prototyper' export default class Generate extends Command { @@ -19,7 +19,7 @@ export default class Generate extends Command { if (flags.features) { const processResult: ProcessResult = JSON.parse(flags.features) as ProcessResult - const generator = new Generator(fs, flags.outputDir) + const generator = new HtmlUIPrototyper(fs, flags.outputDir) const result = await generator.generate(processResult.features) this.log(JSON.stringify(result)) } diff --git a/src/generator.ts b/src/html-ui-prototyper.ts similarity index 84% rename from src/generator.ts rename to src/html-ui-prototyper.ts index 5287802..ec99b85 100644 --- a/src/generator.ts +++ b/src/html-ui-prototyper.ts @@ -6,10 +6,8 @@ const prettier = require('prettier') const cosmiconfig = require('cosmiconfig') import WidgetFactory from './widgets/widget-factory' -// TODO: use "export default" -import { ConfigLoader } from './utils/config_loader' -export default class Generator implements Prototyper { +export default class HtmlUIPrototyper implements Prototyper { constructor(private _fs: any = fs, private _outputDir: string) { } @@ -19,8 +17,9 @@ export default class Generator implements Prototyper { const explorer = cosmiconfig('config') let config = explorer.searchSync() - const configLoader = new ConfigLoader(config) - const factory = new WidgetFactory(configLoader) + // TODO: lançar exceção se arquivo não existir + // TODO: extrair "config" de config + const factory = new WidgetFactory(config.config) let createFilePromises: Promise[] = [] for (let feature of features) { diff --git a/src/index.ts b/src/index.ts index 95bc5ff..48bbdaa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1 @@ -export * from './generator'; +export * from './html-ui-prototyper'; diff --git a/src/interfaces/app-config.ts b/src/interfaces/app-config.ts new file mode 100644 index 0000000..f52efca --- /dev/null +++ b/src/interfaces/app-config.ts @@ -0,0 +1,12 @@ +export interface AppConfig { + widgets?: { + input?: WidgetConfig + } +} + +export interface WidgetConfig { + opening: string, + closure?: string, + wrapperOpening?: string, + wrapperClosure?: string +} diff --git a/src/interfaces/custom_config.ts b/src/interfaces/custom_config.ts deleted file mode 100644 index 390858e..0000000 --- a/src/interfaces/custom_config.ts +++ /dev/null @@ -1,18 +0,0 @@ -export interface CustomConfig { - widgets?: { - input?: WidgetConfig - } -} - -export interface WidgetConfig { - opening: string, - closure?: string, - header?: string, - footer?: string -} - -// path for properties in WidgetConfig to by used in lodash "get" method -export const WIDGET_OPENING = 'opening' -export const WIDGET_CLOSURE = 'closure' -export const WIDGET_WRAPPER_OPENING = 'header' -export const WIDGET_WRAPPER_CLOSURE = 'footer' diff --git a/src/utils/config_loader.ts b/src/utils/config_loader.ts deleted file mode 100644 index 31872d3..0000000 --- a/src/utils/config_loader.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { get } from 'lodash'; -import { CustomConfig, WidgetConfig } from '../interfaces/custom_config'; - -export class ConfigLoader { - constructor(private _config: CustomConfig) {} - - public getInputDefinition(): WidgetConfig { - return get(this._config, 'config.widgets.input') - } -} diff --git a/src/utils/create_label.ts b/src/utils/create-label.ts similarity index 100% rename from src/utils/create_label.ts rename to src/utils/create-label.ts diff --git a/src/utils/index.ts b/src/utils/index.ts index b3430ae..af6df3b 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,2 +1,2 @@ export * from './prop' -export * from './create_label' +export * from './create-label' diff --git a/src/widgets/button.ts b/src/widgets/button.ts index a4d8d8b..67dccf4 100644 --- a/src/widgets/button.ts +++ b/src/widgets/button.ts @@ -2,7 +2,7 @@ import {Widget} from 'concordialang-ui-core' import {formatProperties} from '../utils' -export class Button extends Widget { +export default class Button extends Widget { private readonly VALID_PROPERTIES = ['id', 'disabled', 'value'] constructor(props: any, name?: string) { diff --git a/src/widgets/checkbox.ts b/src/widgets/checkbox.ts index d4866cd..2ffaa10 100644 --- a/src/widgets/checkbox.ts +++ b/src/widgets/checkbox.ts @@ -2,7 +2,7 @@ import {Widget} from 'concordialang-ui-core' import {formatProperties} from '../utils' -export class Checkbox extends Widget { +export default class Checkbox extends Widget { private readonly VALID_PROPERTIES = ['value', 'required'] constructor(props: any, name: string) { diff --git a/src/widgets/input.ts b/src/widgets/input.ts index d855949..9d87424 100644 --- a/src/widgets/input.ts +++ b/src/widgets/input.ts @@ -1,14 +1,8 @@ import { Widget } from 'concordialang-ui-core' import { get } from 'lodash'; +import { WidgetConfig } from '../interfaces/app-config' import { formatProperties, createLabel } from '../utils' -import { - WidgetConfig, - WIDGET_OPENING, - WIDGET_CLOSURE, - WIDGET_WRAPPER_OPENING, - WIDGET_WRAPPER_CLOSURE -} from '../interfaces/custom_config' const enum DataTypes { STRING = 'string', @@ -19,36 +13,25 @@ const enum DataTypes { DATETIME = 'datetime' } -export class Input extends Widget { +export default class Input extends Widget { private readonly VALID_PROPERTIES = ['id', 'editable', 'minlength', 'maxlength', 'required', 'format'] - constructor(props: any, name: string, private _customDefinition?: WidgetConfig) { + constructor(props: any, name: string, private _config: WidgetConfig) { super(props, name) } public renderToString(): string { - const input = this.createInput() - const label = createLabel(this.name, this.props.id.toString()) - return this.wrap(label + input) - } - - private createInput(): string { const inputType = this.getType(this.props.datatype as string) - const inputOpening = get(this._customDefinition, WIDGET_OPENING, 'input') - const inputClosure = get(this._customDefinition, WIDGET_CLOSURE) const properties = formatProperties(this.props, this.VALID_PROPERTIES) - - if (inputClosure) { - return `<${inputOpening} ${inputType} ${properties}>` - } else { - return `<${inputOpening} ${inputType} ${properties}>` - } + const input = this._config.opening.replace('%s', `${ inputType } ${ properties }`) + this._config.closure + const label = createLabel(this.name, this.props.id.toString()) + return this.wrap(label + input) } private wrap(elements: string): string { - const wrapperOpening = get(this._customDefinition, WIDGET_WRAPPER_OPENING, '
') - const wrapperEnclosing = get(this._customDefinition, WIDGET_WRAPPER_CLOSURE, '
') - return wrapperOpening + elements + wrapperEnclosing + if (this._config.wrapperOpening && this._config.wrapperClosure) + return this._config.wrapperOpening + elements + this._config.wrapperClosure + return elements } private getType(datatype: string): string { diff --git a/src/widgets/radio.ts b/src/widgets/radio.ts index 3cebafd..1b6282b 100644 --- a/src/widgets/radio.ts +++ b/src/widgets/radio.ts @@ -2,7 +2,7 @@ import {Widget} from 'concordialang-ui-core' import {formatProperties, createLabel} from '../utils' -export class Radio extends Widget { +export default class Radio extends Widget { private readonly VALID_PROPERTIES = ['value'] constructor(props: any, name: string) { diff --git a/src/widgets/select.ts b/src/widgets/select.ts index d15f47d..42fb725 100644 --- a/src/widgets/select.ts +++ b/src/widgets/select.ts @@ -2,7 +2,7 @@ import {Widget} from 'concordialang-ui-core' import {formatProperties, createLabel} from '../utils' -export class Select extends Widget { +export default class Select extends Widget { private readonly VALID_PROPERTIES = ['id', 'required'] constructor(props: any, name: string) { diff --git a/src/widgets/widget-factory.ts b/src/widgets/widget-factory.ts index 43809af..7bfcfa9 100644 --- a/src/widgets/widget-factory.ts +++ b/src/widgets/widget-factory.ts @@ -1,11 +1,12 @@ import {UiElement, Widget} from 'concordialang-ui-core' +import { get } from 'lodash'; -import {Button} from './button' -import {Input} from './input' -import {Checkbox} from './checkbox' -import {Radio} from './radio' -import {Select} from './select' -import {ConfigLoader} from '../utils/config_loader' +import Button from './button' +import Input from './input' +import Checkbox from './checkbox' +import Radio from './radio' +import Select from './select' +import { AppConfig, WidgetConfig } from '../interfaces/app-config' const enum Widgets { BUTTON = 'button', @@ -16,9 +17,7 @@ const enum Widgets { } export default class WidgetFactory { - // criar uma classe "ConfigLoader" que recebe "config" no construtor - // criar uma interface para "config" - constructor(private _configLoader: ConfigLoader) {} + constructor(private _config: AppConfig) {} create(element: UiElement): Widget { switch (element.widget) { @@ -32,8 +31,7 @@ export default class WidgetFactory { } private createInputElement(element: UiElement): any { - const customInputDefinition = this._configLoader.getInputDefinition() - if (customInputDefinition) return new Input(element.props, element.name, customInputDefinition) - return new Input(element.props, element.name) + const widgetConfig: WidgetConfig = get(this._config, 'widgets.input') + return new Input(element.props, element.name, widgetConfig) } } From bad2094571830e914a054c113f8c35ac451cbcd0 Mon Sep 17 00:00:00 2001 From: Willian Date: Fri, 21 Jun 2019 22:36:01 -0300 Subject: [PATCH 05/12] Add label in widgets folder and refactor the html-ui-prototyper --- dist/html-ui-prototyper.d.ts | 1 + dist/html-ui-prototyper.js | 20 +++++++++------ dist/utils/index.d.ts | 2 -- dist/utils/index.js | 5 ---- dist/widgets/button.js | 4 +-- dist/widgets/checkbox.js | 4 +-- dist/widgets/input.js | 17 +++++++------ .../create-label.d.ts => widgets/label.d.ts} | 0 .../create-label.js => widgets/label.js} | 0 dist/widgets/radio.js | 7 +++--- dist/widgets/select.js | 7 +++--- src/html-ui-prototyper.ts | 25 ++++++++++++------- src/utils/index.ts | 2 -- src/widgets/button.ts | 2 +- src/widgets/checkbox.ts | 2 +- src/widgets/input.ts | 8 +++--- .../create-label.ts => widgets/label.ts} | 0 src/widgets/radio.ts | 3 ++- src/widgets/select.ts | 3 ++- 19 files changed, 62 insertions(+), 50 deletions(-) delete mode 100644 dist/utils/index.d.ts delete mode 100644 dist/utils/index.js rename dist/{utils/create-label.d.ts => widgets/label.d.ts} (100%) rename dist/{utils/create-label.js => widgets/label.js} (100%) delete mode 100644 src/utils/index.ts rename src/{utils/create-label.ts => widgets/label.ts} (100%) diff --git a/dist/html-ui-prototyper.d.ts b/dist/html-ui-prototyper.d.ts index a685f12..0af34f5 100644 --- a/dist/html-ui-prototyper.d.ts +++ b/dist/html-ui-prototyper.d.ts @@ -5,4 +5,5 @@ export default class HtmlUIPrototyper implements Prototyper { constructor(_fs: any, _outputDir: string); generate(features: Feature[]): Promise; private createHtmlFile; + private getAppConfig; } diff --git a/dist/html-ui-prototyper.js b/dist/html-ui-prototyper.js index 0bec5f7..b949dfd 100644 --- a/dist/html-ui-prototyper.js +++ b/dist/html-ui-prototyper.js @@ -14,14 +14,9 @@ class HtmlUIPrototyper { } generate(features) { return tslib_1.__awaiter(this, void 0, void 0, function*() { - // search for a ".configrc.json" - // TODO: replace "config" with the CLI name - const explorer = cosmiconfig('config') - let config = explorer.searchSync() - // TODO: lançar exceção se arquivo não existir - // TODO: extrair "config" de config - const factory = new widget_factory_1.default(config.config) - let createFilePromises = [] + const appConfig = this.getAppConfig() + const factory = new widget_factory_1.default(appConfig) + const createFilePromises = [] for (let feature of features) { const elements = feature.uiElements.map(uiElement => factory.create(uiElement) @@ -51,5 +46,14 @@ class HtmlUIPrototyper { return path }) } + getAppConfig() { + // search for a ".configrc.json" + // TODO: replace "config" with the CLI name + const explorer = cosmiconfig('config') + const configFile = explorer.searchSync() + if (!configFile) throw new Error('Config file not found') + const appConfig = configFile.config + return appConfig + } } exports.default = HtmlUIPrototyper diff --git a/dist/utils/index.d.ts b/dist/utils/index.d.ts deleted file mode 100644 index a263ba0..0000000 --- a/dist/utils/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './prop'; -export * from './create-label'; diff --git a/dist/utils/index.js b/dist/utils/index.js deleted file mode 100644 index bc6c1c1..0000000 --- a/dist/utils/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict' -Object.defineProperty(exports, '__esModule', { value: true }) -const tslib_1 = require('tslib') -tslib_1.__exportStar(require('./prop'), exports) -tslib_1.__exportStar(require('./create-label'), exports) diff --git a/dist/widgets/button.js b/dist/widgets/button.js index 85da2e0..3c35e32 100644 --- a/dist/widgets/button.js +++ b/dist/widgets/button.js @@ -1,7 +1,7 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const utils_1 = require('../utils') +const prop_1 = require('../utils/prop') class Button extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name || '') @@ -9,7 +9,7 @@ class Button extends concordialang_ui_core_1.Widget { } renderToString() { // const inputType = this.getType(this.props.datatype as string) - const properties = utils_1.formatProperties( + const properties = prop_1.formatProperties( this.props, this.VALID_PROPERTIES ) diff --git a/dist/widgets/checkbox.js b/dist/widgets/checkbox.js index 7a1acab..f322947 100644 --- a/dist/widgets/checkbox.js +++ b/dist/widgets/checkbox.js @@ -1,7 +1,7 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const utils_1 = require('../utils') +const prop_1 = require('../utils/prop') class Checkbox extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name) @@ -9,7 +9,7 @@ class Checkbox extends concordialang_ui_core_1.Widget { } // TODO: remove \n renderToString() { - const properties = utils_1.formatProperties( + const properties = prop_1.formatProperties( this.props, this.VALID_PROPERTIES ) diff --git a/dist/widgets/input.js b/dist/widgets/input.js index b91c413..89e7db6 100644 --- a/dist/widgets/input.js +++ b/dist/widgets/input.js @@ -1,7 +1,8 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const utils_1 = require('../utils') +const prop_1 = require('../utils/prop') +const label_1 = require('./label') class Input extends concordialang_ui_core_1.Widget { constructor(props, name, _config) { super(props, name) @@ -17,15 +18,17 @@ class Input extends concordialang_ui_core_1.Widget { } renderToString() { const inputType = this.getType(this.props.datatype) - const properties = utils_1.formatProperties( + const properties = prop_1.formatProperties( this.props, this.VALID_PROPERTIES ) - const input = - this._config.opening.replace('%s', `${inputType} ${properties}`) + - this._config.closure - const label = utils_1.createLabel(this.name, this.props.id.toString()) - return this.wrap(label + input) + const input = this._config.opening.replace( + '%s', + `${inputType} ${properties}` + ) + const inputClosure = this._config.closure || '' + const label = label_1.createLabel(this.name, this.props.id.toString()) + return this.wrap(label + input + inputClosure) } wrap(elements) { if (this._config.wrapperOpening && this._config.wrapperClosure) diff --git a/dist/utils/create-label.d.ts b/dist/widgets/label.d.ts similarity index 100% rename from dist/utils/create-label.d.ts rename to dist/widgets/label.d.ts diff --git a/dist/utils/create-label.js b/dist/widgets/label.js similarity index 100% rename from dist/utils/create-label.js rename to dist/widgets/label.js diff --git a/dist/widgets/radio.js b/dist/widgets/radio.js index 0149439..c1c3c1d 100644 --- a/dist/widgets/radio.js +++ b/dist/widgets/radio.js @@ -1,7 +1,8 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const utils_1 = require('../utils') +const prop_1 = require('../utils/prop') +const label_1 = require('./label') class Radio extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name) @@ -9,12 +10,12 @@ class Radio extends concordialang_ui_core_1.Widget { } // TODO: remove \n renderToString() { - const properties = utils_1.formatProperties( + const properties = prop_1.formatProperties( this.props, this.VALID_PROPERTIES ) let inputs = [] - const label = utils_1.createLabel(this.name, this.props.id.toString()) + const label = label_1.createLabel(this.name, this.props.id.toString()) const inputName = this.name.toLowerCase() if (properties) { for (let value of this.props.value) { diff --git a/dist/widgets/select.js b/dist/widgets/select.js index 5ba0e6b..fc0979c 100644 --- a/dist/widgets/select.js +++ b/dist/widgets/select.js @@ -1,7 +1,8 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') -const utils_1 = require('../utils') +const prop_1 = require('../utils/prop') +const label_1 = require('./label') class Select extends concordialang_ui_core_1.Widget { constructor(props, name) { super(props, name) @@ -9,14 +10,14 @@ class Select extends concordialang_ui_core_1.Widget { } // TODO: remove \n renderToString() { - const properties = utils_1.formatProperties( + const properties = prop_1.formatProperties( this.props, this.VALID_PROPERTIES ) if (!properties) return '
\n\n
' const options = this.getOptions() const select = `\n` - const label = utils_1.createLabel(this.name, this.props.id.toString()) + const label = label_1.createLabel(this.name, this.props.id.toString()) return `
\n${label + select}
` } getOptions() { diff --git a/src/html-ui-prototyper.ts b/src/html-ui-prototyper.ts index ec99b85..ef16687 100644 --- a/src/html-ui-prototyper.ts +++ b/src/html-ui-prototyper.ts @@ -6,21 +6,16 @@ const prettier = require('prettier') const cosmiconfig = require('cosmiconfig') import WidgetFactory from './widgets/widget-factory' +import { AppConfig } from './interfaces/app-config' export default class HtmlUIPrototyper implements Prototyper { constructor(private _fs: any = fs, private _outputDir: string) { } public async generate(features: Feature[]): Promise { - // search for a ".configrc.json" - // TODO: replace "config" with the CLI name - const explorer = cosmiconfig('config') - let config = explorer.searchSync() - - // TODO: lançar exceção se arquivo não existir - // TODO: extrair "config" de config - const factory = new WidgetFactory(config.config) - let createFilePromises: Promise[] = [] + const appConfig: AppConfig = this.getAppConfig() + const factory = new WidgetFactory(appConfig) + const createFilePromises: Promise[] = [] for (let feature of features) { const elements: Widget[] = feature.uiElements.map(uiElement => (factory.create(uiElement))) @@ -41,4 +36,16 @@ export default class HtmlUIPrototyper implements Prototyper { await promisify(fs.writeFile)(path, content) return path } + + private getAppConfig(): AppConfig { + // search for a ".configrc.json" + // TODO: replace "config" with the CLI name + const explorer = cosmiconfig('config') + const configFile = explorer.searchSync() + + if (!configFile) throw new Error('Config file not found') + const appConfig: AppConfig = configFile.config + + return appConfig + } } diff --git a/src/utils/index.ts b/src/utils/index.ts deleted file mode 100644 index af6df3b..0000000 --- a/src/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './prop' -export * from './create-label' diff --git a/src/widgets/button.ts b/src/widgets/button.ts index 67dccf4..b036186 100644 --- a/src/widgets/button.ts +++ b/src/widgets/button.ts @@ -1,6 +1,6 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties} from '../utils' +import {formatProperties} from '../utils/prop' export default class Button extends Widget { private readonly VALID_PROPERTIES = ['id', 'disabled', 'value'] diff --git a/src/widgets/checkbox.ts b/src/widgets/checkbox.ts index 2ffaa10..5e37c09 100644 --- a/src/widgets/checkbox.ts +++ b/src/widgets/checkbox.ts @@ -1,6 +1,6 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties} from '../utils' +import {formatProperties} from '../utils/prop' export default class Checkbox extends Widget { private readonly VALID_PROPERTIES = ['value', 'required'] diff --git a/src/widgets/input.ts b/src/widgets/input.ts index 9d87424..30c07f9 100644 --- a/src/widgets/input.ts +++ b/src/widgets/input.ts @@ -2,7 +2,8 @@ import { Widget } from 'concordialang-ui-core' import { get } from 'lodash'; import { WidgetConfig } from '../interfaces/app-config' -import { formatProperties, createLabel } from '../utils' +import { formatProperties } from '../utils/prop' +import { createLabel } from './label' const enum DataTypes { STRING = 'string', @@ -23,9 +24,10 @@ export default class Input extends Widget { public renderToString(): string { const inputType = this.getType(this.props.datatype as string) const properties = formatProperties(this.props, this.VALID_PROPERTIES) - const input = this._config.opening.replace('%s', `${ inputType } ${ properties }`) + this._config.closure + const input = this._config.opening.replace('%s', `${ inputType } ${ properties }`) + const inputClosure = this._config.closure || '' const label = createLabel(this.name, this.props.id.toString()) - return this.wrap(label + input) + return this.wrap(label + input + inputClosure) } private wrap(elements: string): string { diff --git a/src/utils/create-label.ts b/src/widgets/label.ts similarity index 100% rename from src/utils/create-label.ts rename to src/widgets/label.ts diff --git a/src/widgets/radio.ts b/src/widgets/radio.ts index 1b6282b..60f104d 100644 --- a/src/widgets/radio.ts +++ b/src/widgets/radio.ts @@ -1,6 +1,7 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties, createLabel} from '../utils' +import {formatProperties} from '../utils/prop' +import {createLabel} from './label' export default class Radio extends Widget { private readonly VALID_PROPERTIES = ['value'] diff --git a/src/widgets/select.ts b/src/widgets/select.ts index 42fb725..1994f1e 100644 --- a/src/widgets/select.ts +++ b/src/widgets/select.ts @@ -1,6 +1,7 @@ import {Widget} from 'concordialang-ui-core' -import {formatProperties, createLabel} from '../utils' +import {formatProperties} from '../utils/prop' +import {createLabel} from './label' export default class Select extends Widget { private readonly VALID_PROPERTIES = ['id', 'required'] From fe3ab9218847519558abb43450e44cce799202ee Mon Sep 17 00:00:00 2001 From: Willian Date: Wed, 26 Jun 2019 15:18:55 -0300 Subject: [PATCH 06/12] Expect a "concordialang-ui-html.json" file with the app configuration --- dist/html-ui-prototyper.js | 15 ++++++++------- src/html-ui-prototyper.ts | 17 ++++++++--------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/dist/html-ui-prototyper.js b/dist/html-ui-prototyper.js index b949dfd..1b3ad06 100644 --- a/dist/html-ui-prototyper.js +++ b/dist/html-ui-prototyper.js @@ -47,13 +47,14 @@ class HtmlUIPrototyper { }) } getAppConfig() { - // search for a ".configrc.json" - // TODO: replace "config" with the CLI name - const explorer = cosmiconfig('config') - const configFile = explorer.searchSync() - if (!configFile) throw new Error('Config file not found') - const appConfig = configFile.config - return appConfig + try { + const explorer = cosmiconfig() + const configFile = explorer.loadSync('concordialang-ui-html.json') + const appConfig = configFile.config + return appConfig + } catch (e) { + throw new Error('Config file not found') + } } } exports.default = HtmlUIPrototyper diff --git a/src/html-ui-prototyper.ts b/src/html-ui-prototyper.ts index ef16687..b4a091a 100644 --- a/src/html-ui-prototyper.ts +++ b/src/html-ui-prototyper.ts @@ -38,14 +38,13 @@ export default class HtmlUIPrototyper implements Prototyper { } private getAppConfig(): AppConfig { - // search for a ".configrc.json" - // TODO: replace "config" with the CLI name - const explorer = cosmiconfig('config') - const configFile = explorer.searchSync() - - if (!configFile) throw new Error('Config file not found') - const appConfig: AppConfig = configFile.config - - return appConfig + try { + const explorer = cosmiconfig() + const configFile = explorer.loadSync('concordialang-ui-html.json') + const appConfig: AppConfig = configFile.config + return appConfig + } catch (e) { + throw new Error('Config file not found') + } } } From 7a5e58d23f26c25d54b0313587e00c2ae9039154 Mon Sep 17 00:00:00 2001 From: Willian Date: Wed, 26 Jun 2019 22:28:31 -0300 Subject: [PATCH 07/12] Update input widget test --- test/widgets/input.spec.ts | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/test/widgets/input.spec.ts b/test/widgets/input.spec.ts index 8096c03..ac3d470 100644 --- a/test/widgets/input.spec.ts +++ b/test/widgets/input.spec.ts @@ -1,10 +1,11 @@ import { UiElement } from 'concordialang-ui-core' -import { Input } from '../../src/widgets/input' +import { WidgetConfig } from '../../src/interfaces/app-config' +import Input from '../../src/widgets/input' describe('Input', () => { describe('renderToString', () => { - const defaultProps: UiElement = { + const uiElement: UiElement = { name: 'Username', widget: 'textbox', position: 16, @@ -16,37 +17,26 @@ describe('Input', () => { } } - const subject = (uiElement?: UiElement) => ( - uiElement ? - new Input(uiElement.props, uiElement.name) : - new Input({}) - ) - - it('without properties', () => { - const inputWidget: Input = subject() - expect(inputWidget.renderToString()).toEqual(expect.stringContaining('')) - }) + const widgetConfig: WidgetConfig = { + opening: '', + wrapperOpening: '
', + wrapperClosure: '
' + } it('produces html from an input element with name', async () => { - const inputWidget: Input = subject(defaultProps) - const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringContaining('')) - }) - - it('produces html from an input element without name', async () => { - const inputWidget: Input = subject({ ...defaultProps, name: undefined }) + const inputWidget: Input = new Input(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringContaining('')) + expect(result).toEqual(expect.stringContaining('')) }) it('produces a label for the input element', async () => { - const inputWidget: Input = subject(defaultProps) + const inputWidget: Input = new Input(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() expect(result).toEqual(expect.stringContaining('')) }) it('surrounds the input with a div', () => { - const inputWidget: Input = subject() + const inputWidget: Input = new Input(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() expect(result).toEqual(expect.stringMatching(/^
(.|\s)*<\/div>$/)) }) From 28d66479477827f7fa159cf0d9f06f2d335565bc Mon Sep 17 00:00:00 2001 From: Willian Date: Sat, 29 Jun 2019 15:06:12 -0300 Subject: [PATCH 08/12] Add label definitions in app config --- dist/interfaces/app-config.d.ts | 7 +++++++ dist/utils/prop.d.ts | 1 + dist/utils/prop.js | 1 + dist/widgets/input.js | 8 ++++++-- dist/widgets/label.d.ts | 3 ++- dist/widgets/label.js | 17 ++++++++++++----- dist/widgets/widget-factory.js | 2 ++ src/interfaces/app-config.ts | 11 +++++++++-- src/utils/prop.ts | 2 ++ src/widgets/input.ts | 6 +++--- src/widgets/label.ts | 16 ++++++++++++---- src/widgets/widget-factory.ts | 1 + test/widgets/input.spec.ts | 25 ++++++++++++++++++++++--- test/widgets/widget-factory.spec.ts | 29 ++++++++++++++++++++++------- 14 files changed, 102 insertions(+), 27 deletions(-) diff --git a/dist/interfaces/app-config.d.ts b/dist/interfaces/app-config.d.ts index d56546e..533c6d2 100644 --- a/dist/interfaces/app-config.d.ts +++ b/dist/interfaces/app-config.d.ts @@ -1,6 +1,7 @@ export interface AppConfig { widgets?: { input?: WidgetConfig; + label?: LabelConfig; }; } export interface WidgetConfig { @@ -8,4 +9,10 @@ export interface WidgetConfig { closure?: string; wrapperOpening?: string; wrapperClosure?: string; + label?: LabelConfig; } +interface LabelConfig { + opening: string; + closure: string; +} +export {}; diff --git a/dist/utils/prop.d.ts b/dist/utils/prop.d.ts index c409969..9934699 100644 --- a/dist/utils/prop.d.ts +++ b/dist/utils/prop.d.ts @@ -1 +1,2 @@ +export declare const PROPS_INJECTION_POINT = "%s"; export declare function formatProperties(props: any, validProperties: string[]): string; diff --git a/dist/utils/prop.js b/dist/utils/prop.js index b4c1c4e..131cca6 100644 --- a/dist/utils/prop.js +++ b/dist/utils/prop.js @@ -1,5 +1,6 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) +exports.PROPS_INJECTION_POINT = '%s' function formatProperties(props, validProperties) { const translateProp = key => { switch (key) { diff --git a/dist/widgets/input.js b/dist/widgets/input.js index 89e7db6..901800c 100644 --- a/dist/widgets/input.js +++ b/dist/widgets/input.js @@ -23,11 +23,15 @@ class Input extends concordialang_ui_core_1.Widget { this.VALID_PROPERTIES ) const input = this._config.opening.replace( - '%s', + prop_1.PROPS_INJECTION_POINT, `${inputType} ${properties}` ) const inputClosure = this._config.closure || '' - const label = label_1.createLabel(this.name, this.props.id.toString()) + const label = label_1.createLabel( + this.name, + this.props.id.toString(), + this._config + ) return this.wrap(label + input + inputClosure) } wrap(elements) { diff --git a/dist/widgets/label.d.ts b/dist/widgets/label.d.ts index d914e3a..483a09d 100644 --- a/dist/widgets/label.d.ts +++ b/dist/widgets/label.d.ts @@ -1 +1,2 @@ -export declare function createLabel(name: string, id: string): string; +import { WidgetConfig } from '../interfaces/app-config'; +export declare function createLabel(widgetName: string, widgetId: string, widgetConfig: WidgetConfig): string; diff --git a/dist/widgets/label.js b/dist/widgets/label.js index 125f5ce..5b8099c 100644 --- a/dist/widgets/label.js +++ b/dist/widgets/label.js @@ -1,10 +1,17 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) -function createLabel(name, id) { - const validIdPattern = /^(#|~|\d|\w).*/ - const labelFor = validIdPattern.test(id) - ? `for="${id.replace(/^#|~/, '')}"` +const prop_1 = require('../utils/prop') +function createLabel(widgetName, widgetId, widgetConfig) { + if (!widgetConfig.label) return '' + const idPattern = /^(#|~|\d|\w).*/ + const labelFor = widgetId.match(idPattern) + ? `for="${widgetId.replace(/^#|~/, '')}"` : '' - return `` + const labelOpening = widgetConfig.label.opening.replace( + prop_1.PROPS_INJECTION_POINT, + labelFor + ) + const labelClosure = widgetConfig.label.closure + return labelOpening + widgetName + labelClosure } exports.createLabel = createLabel diff --git a/dist/widgets/widget-factory.js b/dist/widgets/widget-factory.js index f188a64..f5a1d63 100644 --- a/dist/widgets/widget-factory.js +++ b/dist/widgets/widget-factory.js @@ -28,6 +28,8 @@ class WidgetFactory { } createInputElement(element) { const widgetConfig = lodash_1.get(this._config, 'widgets.input') + widgetConfig.label = + widgetConfig.label || lodash_1.get(this._config, 'widgets.label') return new input_1.default(element.props, element.name, widgetConfig) } } diff --git a/src/interfaces/app-config.ts b/src/interfaces/app-config.ts index f52efca..59c2086 100644 --- a/src/interfaces/app-config.ts +++ b/src/interfaces/app-config.ts @@ -1,6 +1,7 @@ export interface AppConfig { widgets?: { - input?: WidgetConfig + input?: WidgetConfig, + label?: LabelConfig } } @@ -8,5 +9,11 @@ export interface WidgetConfig { opening: string, closure?: string, wrapperOpening?: string, - wrapperClosure?: string + wrapperClosure?: string, + label?: LabelConfig +} + +interface LabelConfig { + opening: string, + closure: string } diff --git a/src/utils/prop.ts b/src/utils/prop.ts index 5741272..f2ad5d1 100644 --- a/src/utils/prop.ts +++ b/src/utils/prop.ts @@ -1,3 +1,5 @@ +export const PROPS_INJECTION_POINT = '%s' + export function formatProperties(props: any, validProperties: string[]): string { const translateProp = (key: string) => { switch(key) { diff --git a/src/widgets/input.ts b/src/widgets/input.ts index 30c07f9..4c9cc09 100644 --- a/src/widgets/input.ts +++ b/src/widgets/input.ts @@ -2,7 +2,7 @@ import { Widget } from 'concordialang-ui-core' import { get } from 'lodash'; import { WidgetConfig } from '../interfaces/app-config' -import { formatProperties } from '../utils/prop' +import { formatProperties, PROPS_INJECTION_POINT } from '../utils/prop' import { createLabel } from './label' const enum DataTypes { @@ -24,9 +24,9 @@ export default class Input extends Widget { public renderToString(): string { const inputType = this.getType(this.props.datatype as string) const properties = formatProperties(this.props, this.VALID_PROPERTIES) - const input = this._config.opening.replace('%s', `${ inputType } ${ properties }`) + const input = this._config.opening.replace(PROPS_INJECTION_POINT, `${ inputType } ${ properties }`) const inputClosure = this._config.closure || '' - const label = createLabel(this.name, this.props.id.toString()) + const label = createLabel(this.name, this.props.id.toString(), this._config) return this.wrap(label + input + inputClosure) } diff --git a/src/widgets/label.ts b/src/widgets/label.ts index 51f1061..0cf8a88 100644 --- a/src/widgets/label.ts +++ b/src/widgets/label.ts @@ -1,5 +1,13 @@ -export function createLabel(name: string, id: string): string { - const validIdPattern = /^(#|~|\d|\w).*/ - const labelFor = (validIdPattern.test(id)) ? `for="${id.replace(/^#|~/ , '')}"` : '' - return `` +import { WidgetConfig } from '../interfaces/app-config' +import { PROPS_INJECTION_POINT } from '../utils/prop' + +export function createLabel(widgetName: string, widgetId: string, widgetConfig: WidgetConfig): string { + if (!widgetConfig.label) return '' + + const idPattern = /^(#|~|\d|\w).*/ + const labelFor = (widgetId.match(idPattern)) ? `for="${widgetId.replace(/^#|~/ , '')}"` : '' + const labelOpening = widgetConfig.label.opening.replace(PROPS_INJECTION_POINT, labelFor) + const labelClosure = widgetConfig.label.closure + + return labelOpening + widgetName + labelClosure } diff --git a/src/widgets/widget-factory.ts b/src/widgets/widget-factory.ts index 7bfcfa9..ad16ba5 100644 --- a/src/widgets/widget-factory.ts +++ b/src/widgets/widget-factory.ts @@ -32,6 +32,7 @@ export default class WidgetFactory { private createInputElement(element: UiElement): any { const widgetConfig: WidgetConfig = get(this._config, 'widgets.input') + widgetConfig.label = widgetConfig.label || get(this._config, 'widgets.label') return new Input(element.props, element.name, widgetConfig) } } diff --git a/test/widgets/input.spec.ts b/test/widgets/input.spec.ts index ac3d470..833f71f 100644 --- a/test/widgets/input.spec.ts +++ b/test/widgets/input.spec.ts @@ -1,6 +1,7 @@ import { UiElement } from 'concordialang-ui-core' -import { WidgetConfig } from '../../src/interfaces/app-config' +import { AppConfig, WidgetConfig } from '../../src/interfaces/app-config' import Input from '../../src/widgets/input' +import { getAppConfig } from '../test-helpers/app-config' describe('Input', () => { @@ -20,7 +21,11 @@ describe('Input', () => { const widgetConfig: WidgetConfig = { opening: '', wrapperOpening: '
', - wrapperClosure: '
' + wrapperClosure: '
', + label: { + opening: '' + } } it('produces html from an input element with name', async () => { @@ -35,10 +40,24 @@ describe('Input', () => { expect(result).toEqual(expect.stringContaining('')) }) - it('surrounds the input with a div', () => { + it('produces a wrapper for the input element', () => { const inputWidget: Input = new Input(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() expect(result).toEqual(expect.stringMatching(/^
(.|\s)*<\/div>$/)) }) + + describe('when the label is not defined', () => { + const widgetConfig: WidgetConfig = { + opening: '', + wrapperOpening: '
', + wrapperClosure: '
' + } + + it('does not produce a label for the input element', async () => { + const inputWidget: Input = new Input(uiElement.props, uiElement.name, widgetConfig) + const result = inputWidget.renderToString() + expect(result).not.toEqual(expect.stringContaining('label')) + }) + }) }) }) diff --git a/test/widgets/widget-factory.spec.ts b/test/widgets/widget-factory.spec.ts index 9354c1a..74167ed 100644 --- a/test/widgets/widget-factory.spec.ts +++ b/test/widgets/widget-factory.spec.ts @@ -1,12 +1,25 @@ import { UiElement } from 'concordialang-ui-core' +import { AppConfig, WidgetConfig } from '../../src/interfaces/app-config' import WidgetFactory from '../../src/widgets/widget-factory' -import { Button } from '../../src/widgets/button'; -import { Input } from '../../src/widgets/input'; +import Button from '../../src/widgets/button'; +import Input from '../../src/widgets/input'; describe('WidgetFactory', () => { - let widgetFactory: WidgetFactory = new WidgetFactory() + const appConfig: AppConfig = { + widgets: { + input: { + opening: '', + label: { + opening: '' + } + } + } + } + + let widgetFactory: WidgetFactory = new WidgetFactory(appConfig) describe('create', () => { it('create button with valid properties', () => { @@ -18,10 +31,10 @@ describe('WidgetFactory', () => { } const buttonWidget = new Button(buttonUiElement.props, buttonUiElement.name) - + expect(widgetFactory.create(buttonUiElement)).toEqual(buttonWidget) }) - + it('create input with valid properties', async () => { const inputUiElement: UiElement = { name: 'Username', @@ -33,15 +46,17 @@ describe('WidgetFactory', () => { minlength: 10 } } + const widgetConfig: WidgetConfig = appConfig.widgets.input + + const inputWidget = new Input(inputUiElement.props, inputUiElement.name, widgetConfig) - const inputWidget = new Input(inputUiElement.props, inputUiElement.name) - expect(widgetFactory.create(inputUiElement)).toEqual(inputWidget) }) it('throw invalid widget error', async () => { const inputUiElement: UiElement = { widget: 'invalid', + name: '', position: 16, props: {} } From 04a06022f47a6e4a381affcb897d966901127dd6 Mon Sep 17 00:00:00 2001 From: Willian Date: Mon, 1 Jul 2019 22:12:37 -0300 Subject: [PATCH 09/12] Generate all widgets based on config file --- package-lock.json | 5 +++ package.json | 1 + src/interfaces/app-config.ts | 5 +++ src/utils/prop.ts | 23 ++---------- src/widgets/button.ts | 34 +++++++++--------- src/widgets/checkbox.ts | 19 +++++----- src/widgets/input.ts | 11 ++---- src/widgets/label.ts | 2 +- src/widgets/radio.ts | 41 ++++++++++++--------- src/widgets/select.ts | 37 +++++++++++-------- src/widgets/widget-factory.ts | 33 ++++++++++++++--- src/widgets/wrapper.ts | 7 ++++ test/commands/generate.spec.ts | 7 ++-- test/generator.spec.ts | 20 ++++++----- test/utils/format-properties.spec.ts | 18 ++++++++++ test/widgets/button.spec.ts | 25 ++++++++----- test/widgets/checkbox.spec.ts | 42 ++++++++++------------ test/widgets/input.spec.ts | 2 -- test/widgets/prop.spec.ts | 2 +- test/widgets/radio.spec.ts | 48 ++++++++++++------------- test/widgets/select.spec.ts | 53 +++++++++++++++------------- 21 files changed, 248 insertions(+), 187 deletions(-) create mode 100644 src/widgets/wrapper.ts create mode 100644 test/utils/format-properties.spec.ts diff --git a/package-lock.json b/package-lock.json index b71ba09..e4ee447 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1532,6 +1532,11 @@ "redeyed": "~2.1.0" } }, + "case": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.1.tgz", + "integrity": "sha512-N0rDB5ftMDKANGsIBRWPWcG0VIKtirgqcXb2vKFi66ySAjXVEwbfCN7ass1mkdXO8fbol3RfbWlQ9KyBX2F/Gg==" + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", diff --git a/package.json b/package.json index 1b193f6..4078409 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "@oclif/command": "^1.5.12", "@oclif/config": "^1.12.12", "@types/lodash": "^4.14.134", + "case": "^1.6.1", "concordialang-ui-core": "^0.2.3", "cosmiconfig": "^5.2.1", "lodash": "^4.17.11", diff --git a/src/interfaces/app-config.ts b/src/interfaces/app-config.ts index 59c2086..b462f6f 100644 --- a/src/interfaces/app-config.ts +++ b/src/interfaces/app-config.ts @@ -1,6 +1,9 @@ export interface AppConfig { widgets?: { input?: WidgetConfig, + radio?: WidgetConfig, + checkbox?: WidgetConfig, + select?: WidgetConfig, label?: LabelConfig } } @@ -8,6 +11,8 @@ export interface AppConfig { export interface WidgetConfig { opening: string, closure?: string, + optionOpening?: string, + optionClosure?: string, wrapperOpening?: string, wrapperClosure?: string, label?: LabelConfig diff --git a/src/utils/prop.ts b/src/utils/prop.ts index f2ad5d1..15d322f 100644 --- a/src/utils/prop.ts +++ b/src/utils/prop.ts @@ -1,3 +1,5 @@ +import { camel } from 'case' + export const PROPS_INJECTION_POINT = '%s' export function formatProperties(props: any, validProperties: string[]): string { @@ -9,26 +11,7 @@ export function formatProperties(props: any, validProperties: string[]): string } const getFormattedProp = (key: string) => { - let value = props[key] - const invalidIdPattern = /^\/\// - - if(key === 'id') { - let newKey = key - // TODO: replace test wit str.match(pattern) - if(!invalidIdPattern.test(value)) { - const validIdPattern = /^#|~/ - const validClassPattern = /^\./ - - if(validIdPattern.test(value)) { - value = value.toString().replace(validIdPattern, '') - } else if(validClassPattern.test(value)) { - newKey = 'class' - value = value.toString().replace(validClassPattern, '') - } - return `${translateProp(newKey)}="${value}"` - } - } - + let value = camel(props[key].toString()) return `${translateProp(key)}="${value}"` } diff --git a/src/widgets/button.ts b/src/widgets/button.ts index b036186..8a93ff9 100644 --- a/src/widgets/button.ts +++ b/src/widgets/button.ts @@ -1,22 +1,24 @@ -import {Widget} from 'concordialang-ui-core' - -import {formatProperties} from '../utils/prop' +import { Widget } from 'concordialang-ui-core' +import { WidgetConfig } from '../interfaces/app-config' +import { formatProperties, PROPS_INJECTION_POINT } from '../utils/prop' export default class Button extends Widget { - private readonly VALID_PROPERTIES = ['id', 'disabled', 'value'] + private readonly VALID_PROPERTIES = ['id', 'disabled', 'value'] - constructor(props: any, name?: string) { - super(props, name || '') - } + constructor(props: any, name: string, private _config: WidgetConfig) { + super(props, name || '') + } - public renderToString(): string { - // const inputType = this.getType(this.props.datatype as string) - const properties = formatProperties(this.props, this.VALID_PROPERTIES) - // return `` - return `` - } + public renderToString(): string { + const buttonType = this.getType(this.props.datatype as string) + let properties = formatProperties(this.props, this.VALID_PROPERTIES) + properties = `${ buttonType } ${ properties }` + const buttonOpening = this._config.opening.replace(PROPS_INJECTION_POINT, properties) + const buttonClosure = this._config.closure + return buttonOpening + this.name + buttonClosure + } - private getType(datatype: string): string { - return `type="${datatype || 'button'}"` - } + private getType(datatype: string): string { + return `type="${datatype || 'button'}"` + } } diff --git a/src/widgets/checkbox.ts b/src/widgets/checkbox.ts index 5e37c09..4c78bca 100644 --- a/src/widgets/checkbox.ts +++ b/src/widgets/checkbox.ts @@ -1,18 +1,21 @@ -import {Widget} from 'concordialang-ui-core' - -import {formatProperties} from '../utils/prop' +import { Widget } from 'concordialang-ui-core' +import { WidgetConfig } from '../interfaces/app-config' +import { formatProperties, PROPS_INJECTION_POINT } from '../utils/prop' +import { wrap } from './wrapper' export default class Checkbox extends Widget { private readonly VALID_PROPERTIES = ['value', 'required'] - constructor(props: any, name: string) { + constructor(props: any, name: string, private _config: WidgetConfig) { super(props, name) } - // TODO: remove \n public renderToString(): string { - const properties = formatProperties(this.props, this.VALID_PROPERTIES) - if (properties) return `
\n${this.name}\n
` - return `
\n${this.name}\n
` + const inputType = 'type="checkbox"' + let properties = formatProperties(this.props, this.VALID_PROPERTIES) + properties = `${inputType} ${properties}` + const inputOpening = this._config.opening.replace(PROPS_INJECTION_POINT, properties) + const inputClosure = this._config.closure || '' + return wrap(inputOpening + this.name + inputClosure, this._config) } } diff --git a/src/widgets/input.ts b/src/widgets/input.ts index 4c9cc09..adb938e 100644 --- a/src/widgets/input.ts +++ b/src/widgets/input.ts @@ -4,6 +4,7 @@ import { get } from 'lodash'; import { WidgetConfig } from '../interfaces/app-config' import { formatProperties, PROPS_INJECTION_POINT } from '../utils/prop' import { createLabel } from './label' +import { wrap } from './wrapper' const enum DataTypes { STRING = 'string', @@ -24,16 +25,10 @@ export default class Input extends Widget { public renderToString(): string { const inputType = this.getType(this.props.datatype as string) const properties = formatProperties(this.props, this.VALID_PROPERTIES) - const input = this._config.opening.replace(PROPS_INJECTION_POINT, `${ inputType } ${ properties }`) + const inputOpening = this._config.opening.replace(PROPS_INJECTION_POINT, `${ inputType } ${ properties }`) const inputClosure = this._config.closure || '' const label = createLabel(this.name, this.props.id.toString(), this._config) - return this.wrap(label + input + inputClosure) - } - - private wrap(elements: string): string { - if (this._config.wrapperOpening && this._config.wrapperClosure) - return this._config.wrapperOpening + elements + this._config.wrapperClosure - return elements + return wrap(label + inputOpening + inputClosure, this._config) } private getType(datatype: string): string { diff --git a/src/widgets/label.ts b/src/widgets/label.ts index 0cf8a88..a75a5e2 100644 --- a/src/widgets/label.ts +++ b/src/widgets/label.ts @@ -5,7 +5,7 @@ export function createLabel(widgetName: string, widgetId: string, widgetConfig: if (!widgetConfig.label) return '' const idPattern = /^(#|~|\d|\w).*/ - const labelFor = (widgetId.match(idPattern)) ? `for="${widgetId.replace(/^#|~/ , '')}"` : '' + const labelFor = widgetId.match(idPattern) ? `for="${widgetId.replace(/^#|~/ , '')}"` : '' const labelOpening = widgetConfig.label.opening.replace(PROPS_INJECTION_POINT, labelFor) const labelClosure = widgetConfig.label.closure diff --git a/src/widgets/radio.ts b/src/widgets/radio.ts index 60f104d..0044ec3 100644 --- a/src/widgets/radio.ts +++ b/src/widgets/radio.ts @@ -1,30 +1,37 @@ -import {Widget} from 'concordialang-ui-core' - -import {formatProperties} from '../utils/prop' -import {createLabel} from './label' +import { Widget } from 'concordialang-ui-core' +import { WidgetConfig } from '../interfaces/app-config' +import { formatProperties, PROPS_INJECTION_POINT } from '../utils/prop' +import { createLabel } from './label' +import { wrap } from './wrapper' export default class Radio extends Widget { - private readonly VALID_PROPERTIES = ['value'] + private readonly VALID_PROPERTIES = [ 'value' ] - constructor(props: any, name: string) { + constructor(props: any, name: string, private _config: WidgetConfig) { super(props, name) } - // TODO: remove \n public renderToString(): string { - const properties = formatProperties(this.props, this.VALID_PROPERTIES) + const inputType = 'type="radio"' + const label = createLabel(this.name, '', this._config) let inputs: String[] = [] - const label = createLabel(this.name, this.props.id.toString()) - const inputName = this.name.toLowerCase() - if (properties) { - for (let value of this.props.value as Array) { - let input = `${value}` - inputs.push(input) - } - return `
\n${label + inputs.join('\n')}\n
` + for (let value of this.props.value as Array) { + // TODO: o que fazer no formatProperties em relação ao value? + // provavelmente terei que instalar o pacote "case" + // para ter 'value="algumaCoisa"', quando value for "Alguma Coisa" + // + // TODO: adicionar propriedades 'id' e 'nome' + + const props = Object.assign({}, this.props, { value }) + let properties = formatProperties(props, this.VALID_PROPERTIES) + properties = `${inputType} ${properties}` + const inputOpening = this._config.opening.replace(PROPS_INJECTION_POINT, properties) + const inputClosure = this._config.closure || '' + inputs.push(inputOpening + value + inputClosure) } - return '
\n\n
' + + return wrap(label + inputs.join(''), this._config) } } diff --git a/src/widgets/select.ts b/src/widgets/select.ts index 1994f1e..856a86f 100644 --- a/src/widgets/select.ts +++ b/src/widgets/select.ts @@ -1,31 +1,38 @@ -import {Widget} from 'concordialang-ui-core' - -import {formatProperties} from '../utils/prop' -import {createLabel} from './label' +import { Widget } from 'concordialang-ui-core' +import { WidgetConfig } from '../interfaces/app-config' +import { formatProperties, PROPS_INJECTION_POINT } from '../utils/prop' +import { createLabel } from './label' +import { wrap } from './wrapper' export default class Select extends Widget { - private readonly VALID_PROPERTIES = ['id', 'required'] + private readonly SELECT_VALID_PROPERTIES = ['id', 'required'] + private readonly OPTION_VALID_PROPERTIES = ['value'] - constructor(props: any, name: string) { + constructor(props: any, name: string, private _config: WidgetConfig) { super(props, name) } - // TODO: remove \n public renderToString(): string { - const properties = formatProperties(this.props, this.VALID_PROPERTIES) - if (!properties) return '
\n\n
' + const properties = formatProperties(this.props, this.SELECT_VALID_PROPERTIES) + const selectOpening = this._config.opening.replace(PROPS_INJECTION_POINT, properties) + const selectClosure = this._config.closure const options = this.getOptions() - const select = `\n` - const label = createLabel(this.name, this.props.id.toString()) - return `
\n${label + select}
` + const select = selectOpening + options + selectClosure + const label = createLabel(this.name, this.props.id.toString(), this._config) + return wrap(label + select, this._config) } private getOptions(): string { + if (!this._config.optionOpening) return '' + let options: string[] = [] for (let value of this.props.value as Array) { - let option = `` - options.push(option) + const optionProps = { value } + const properties = formatProperties(optionProps, this.OPTION_VALID_PROPERTIES) + const optionOpening = this._config.optionOpening.replace(PROPS_INJECTION_POINT, properties) + const optionClosure = this._config.optionClosure + options.push(optionOpening + value + optionClosure) } - return options.join('\n') + return options.join('') } } diff --git a/src/widgets/widget-factory.ts b/src/widgets/widget-factory.ts index ad16ba5..e6dca4c 100644 --- a/src/widgets/widget-factory.ts +++ b/src/widgets/widget-factory.ts @@ -22,17 +22,40 @@ export default class WidgetFactory { create(element: UiElement): Widget { switch (element.widget) { case Widgets.TEXTBOX: return this.createInputElement(element) - case Widgets.BUTTON: return new Button(element.props, element.name) - case Widgets.CHECKBOX: return new Checkbox(element.props, element.name) - case Widgets.RADIO: return new Radio(element.props, element.name) - case Widgets.SELECT: return new Select(element.props, element.name) + case Widgets.BUTTON: return this.createButtonElement(element) + case Widgets.CHECKBOX: return this.createCheckboxElement(element) + case Widgets.RADIO: return this.createRadioElement(element) + case Widgets.SELECT: return this.createSelectElement(element) default: throw new Error(`Invalid widget type: ${element.widget}`) } } - private createInputElement(element: UiElement): any { + private createInputElement(element: UiElement): Input { const widgetConfig: WidgetConfig = get(this._config, 'widgets.input') widgetConfig.label = widgetConfig.label || get(this._config, 'widgets.label') return new Input(element.props, element.name, widgetConfig) } + + private createRadioElement(element: UiElement): Radio { + const widgetConfig: WidgetConfig = get(this._config, 'widgets.radio') + widgetConfig.label = widgetConfig.label || get(this._config, 'widgets.label') + return new Radio(element.props, element.name, widgetConfig) + } + + private createCheckboxElement(element: UiElement): Checkbox { + const widgetConfig: WidgetConfig = get(this._config, 'widgets.checkbox') + widgetConfig.label = widgetConfig.label || get(this._config, 'widgets.label') + return new Checkbox(element.props, element.name, widgetConfig) + } + + private createSelectElement(element: UiElement): Select { + const widgetConfig: WidgetConfig = get(this._config, 'widgets.select') + widgetConfig.label = widgetConfig.label || get(this._config, 'widgets.label') + return new Select(element.props, element.name, widgetConfig) + } + + private createButtonElement(element: UiElement): Button { + const widgetConfig: WidgetConfig = get(this._config, 'widgets.button') + return new Button(element.props, element.name, widgetConfig) + } } diff --git a/src/widgets/wrapper.ts b/src/widgets/wrapper.ts new file mode 100644 index 0000000..5925db1 --- /dev/null +++ b/src/widgets/wrapper.ts @@ -0,0 +1,7 @@ +import { WidgetConfig } from '../interfaces/app-config' + +export function wrap(elements: string, widgetConfig: WidgetConfig): string { + if (widgetConfig.wrapperOpening && widgetConfig.wrapperClosure) + return widgetConfig.wrapperOpening + elements + widgetConfig.wrapperClosure + return elements +} diff --git a/test/commands/generate.spec.ts b/test/commands/generate.spec.ts index fd7d496..f6e04f0 100644 --- a/test/commands/generate.spec.ts +++ b/test/commands/generate.spec.ts @@ -4,9 +4,8 @@ describe('Generate', () => { it('should print a JSON content', async () => { let spy = jest.spyOn(process.stdout, 'write'); - await Generate.run([]) // TODO: pass a parameter - // expect(spy).toBeCalledWith({}) - expect(spy).not.toBeCalled() // TODO: change this assertion + await Generate.run(['--features', '[]', '--outputDir', 'outputDir']) + expect(spy).not.toBeCalled() }) -}) \ No newline at end of file +}) diff --git a/test/generator.spec.ts b/test/generator.spec.ts index d574429..b917c69 100644 --- a/test/generator.spec.ts +++ b/test/generator.spec.ts @@ -3,29 +3,31 @@ import { minify } from 'html-minifier' import { fs, vol } from 'memfs' import { promisify } from 'util' -import Generator from '../src/generator' +import HtmlUIPrototyper from '../src/html-ui-prototyper' -describe('Generator', () => { +describe('HtmlUIPrototyper', () => { const CURRENT_DIR: string = process.cwd() - let generator: Generator | null + let prototyper: HtmlUIPrototyper | null beforeEach(() => { - vol.mkdirpSync(CURRENT_DIR) // Synchronize with the current fs structure - generator = new Generator(fs) // In-memory fs + vol.fromJSON({ + '/concordialang-ui-html.json': '{}' + }, CURRENT_DIR) + prototyper = new HtmlUIPrototyper(fs, CURRENT_DIR) // In-memory fs }) afterEach(() => { vol.reset() // Erase in-memory structure - generator = null + prototyper = null }) async function expectFeaturesToProduceHtml(features: Feature[], htmls: string[]): Promise { - if (! generator) { - generator = new Generator(fs) + if (! prototyper) { + prototyper = new HtmlUIPrototyper(fs, CURRENT_DIR) } - const files: string[] = await generator.generate(features) + const files: string[] = await prototyper.generate(features) expect(files).toHaveLength(htmls.length) // tslint:disable-next-line:forin for (let i in files) { diff --git a/test/utils/format-properties.spec.ts b/test/utils/format-properties.spec.ts new file mode 100644 index 0000000..17bc7ae --- /dev/null +++ b/test/utils/format-properties.spec.ts @@ -0,0 +1,18 @@ +import { formatProperties } from '../../src/utils/prop' + +describe('formatProperties', () => { + describe('when there is an invalid property', () => { + const props = { + id: 'id', + name: 'name', + required: true, + foo: 'bar' + } + + const validProperties = ['id', 'name', 'required'] + + it('produces a string with the valid properties only', () => { + expect(formatProperties(props, validProperties)).toEqual('id="id" name="name" required="true"') + }) + }) +}) diff --git a/test/widgets/button.spec.ts b/test/widgets/button.spec.ts index d3c0d99..c46a90f 100644 --- a/test/widgets/button.spec.ts +++ b/test/widgets/button.spec.ts @@ -1,20 +1,29 @@ import { UiElement} from 'concordialang-ui-core' -import { Button } from '../../src/widgets/button' +import { AppConfig, WidgetConfig } from '../../src/interfaces/app-config' +import Button from '../../src/widgets/button' describe('Button', () => { describe('renderToString', () => { - it('without properties', () => { - const b = new Button({}) - expect(b.renderToString()).toBe('') - }) + const uiElement: UiElement = { + name: 'Save', + widget: 'button', + position: 7, + props: { + id: 'save' + } + } + + const widgetConfig: WidgetConfig = { + opening: '' + } it('produces html from a button element', async () => { - const buttonUiElement: UiElement = { name: 'OK', widget: 'button', position: 30, props: {} } - const buttonWidget: Button = new Button(buttonUiElement.props, buttonUiElement.name) + const buttonWidget: Button = new Button(uiElement.props, uiElement.name, widgetConfig) const result = buttonWidget.renderToString() - expect(result).toEqual(``) + expect(result).toEqual(``) }) }) }) diff --git a/test/widgets/checkbox.spec.ts b/test/widgets/checkbox.spec.ts index 84e1b1b..5bea6c6 100644 --- a/test/widgets/checkbox.spec.ts +++ b/test/widgets/checkbox.spec.ts @@ -1,10 +1,11 @@ import { UiElement } from 'concordialang-ui-core' -import { Checkbox } from '../../src/widgets/checkbox' +import { AppConfig, WidgetConfig } from '../../src/interfaces/app-config' +import Checkbox from '../../src/widgets/checkbox' describe('Checkbox', () => { describe('renderToString', () => { - const defaultProps: UiElement = { + const uiElement: UiElement = { name: 'Web Developer', widget: 'checkbox', position: 16, @@ -13,33 +14,26 @@ describe('Checkbox', () => { } } - const subject = (uiElement?: UiElement) => ( - uiElement ? - new Checkbox(uiElement.props, uiElement.name) : - new Checkbox({}) - ) + const widgetConfig: WidgetConfig = { + opening: '', + wrapperOpening: '
', + wrapperClosure: '
', + label: { + opening: '' + } + } - it('without properties', () => { - const inputWidget: Checkbox = subject() - expect(inputWidget.renderToString()).toEqual(expect.stringContaining('')) + it('produces html from an input element with name', async () => { + const inputWidget: Checkbox = new Checkbox(uiElement.props, uiElement.name, widgetConfig) + const result = inputWidget.renderToString() + expect(result).toEqual(expect.stringContaining('Web Developer')) }) - it('surrounds the input with a div', () => { - const inputWidget: Checkbox = subject() + it('produces a wrapper for the input element', () => { + const inputWidget: Checkbox = new Checkbox(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() expect(result).toEqual(expect.stringMatching(/^
(.|\s)*<\/div>$/)) }) - - it('produces html from an input element with name', async () => { - const inputWidget: Checkbox = subject(defaultProps) - const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringContaining('Web Developer')) - }) - - it('produces html from an input element without name', async () => { - const inputWidget: Checkbox = subject({ ...defaultProps, name: undefined }) - const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringMatching('\n')) - }) }) }) diff --git a/test/widgets/input.spec.ts b/test/widgets/input.spec.ts index 833f71f..c68fb18 100644 --- a/test/widgets/input.spec.ts +++ b/test/widgets/input.spec.ts @@ -1,10 +1,8 @@ import { UiElement } from 'concordialang-ui-core' import { AppConfig, WidgetConfig } from '../../src/interfaces/app-config' import Input from '../../src/widgets/input' -import { getAppConfig } from '../test-helpers/app-config' describe('Input', () => { - describe('renderToString', () => { const uiElement: UiElement = { name: 'Username', diff --git a/test/widgets/prop.spec.ts b/test/widgets/prop.spec.ts index fccdacd..d0e748a 100644 --- a/test/widgets/prop.spec.ts +++ b/test/widgets/prop.spec.ts @@ -1,4 +1,4 @@ -import { formatProperties } from '../../src/widgets/prop' +import { formatProperties } from '../../src/utils/prop' describe('formatProperties', () => { it('creates a string with the valid properties', () => { diff --git a/test/widgets/radio.spec.ts b/test/widgets/radio.spec.ts index fa9286e..1e5c73d 100644 --- a/test/widgets/radio.spec.ts +++ b/test/widgets/radio.spec.ts @@ -1,9 +1,10 @@ import { UiElement } from 'concordialang-ui-core' -import { Radio } from '../../src/widgets/radio' +import { AppConfig, WidgetConfig } from '../../src/interfaces/app-config' +import Radio from '../../src/widgets/radio' describe('Radio', () => { describe('renderToString', () => { - const defaultProps: UiElement = { + const uiElement: UiElement = { name: 'Gender', widget: 'radio', position: 7, @@ -13,34 +14,33 @@ describe('Radio', () => { } } - const subject = (uiElement?: UiElement) => ( - uiElement ? - new Radio(uiElement.props, uiElement.name) : - new Radio({}) - ) + const widgetConfig: WidgetConfig = { + opening: '', + wrapperOpening: '
', + wrapperClosure: '
', + label: { + opening: '' + } + } - it('without properties', () => { - const inputWidget: Radio = subject() - expect(inputWidget.renderToString()).toEqual(expect.stringContaining('')) + it('produces html from an radio element with name', async () => { + const inputWidget: Radio = new Radio(uiElement.props, uiElement.name, widgetConfig) + const result = inputWidget.renderToString() + expect(result).toEqual(expect.stringContaining('Male')) + expect(result).toEqual(expect.stringContaining('Female')) }) - it('surrounds the input with a div', () => { - const inputWidget: Radio = subject() - const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringMatching(/^
(.|\s)*<\/div>$/)) - }) - - it('produces html from an input element with name', async () => { - const inputWidget: Radio = subject(defaultProps) + it('produces a label for the input element', async () => { + const inputWidget: Radio = new Radio(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringContaining('Male')) - expect(result).toEqual(expect.stringContaining('Female')) - }) + expect(result).toEqual(expect.stringContaining('')) + }) - it('produces a label for the select element', async () => { - const inputWidget: Radio = subject(defaultProps) + it('produces a wrapper for the input element', () => { + const inputWidget: Radio = new Radio(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringContaining('')) + expect(result).toEqual(expect.stringMatching(/^
(.|\s)*<\/div>$/)) }) }) }) diff --git a/test/widgets/select.spec.ts b/test/widgets/select.spec.ts index 637656c..eca3546 100644 --- a/test/widgets/select.spec.ts +++ b/test/widgets/select.spec.ts @@ -1,9 +1,10 @@ import { UiElement } from 'concordialang-ui-core' -import { Select } from '../../src/widgets/select' +import { AppConfig, WidgetConfig } from '../../src/interfaces/app-config' +import Select from '../../src/widgets/select' describe('Select', () => { describe('renderToString', () => { - const defaultProps: UiElement = { + const uiElement: UiElement = { name: 'Gender', widget: 'select', position: 7, @@ -13,41 +14,43 @@ describe('Select', () => { } } - const subject = (uiElement?: UiElement) => ( - uiElement ? - new Select(uiElement.props, uiElement.name) : - new Select({}) - ) - - it('without properties', () => { - const inputWidget: Select = subject() - expect(inputWidget.renderToString()).toEqual(expect.stringContaining('')) - }) - - it('surrounds the select with a div', () => { - const inputWidget: Select = subject() - const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringMatching(/^
(.|\s)*<\/div>$/)) - }) + const widgetConfig: WidgetConfig = { + opening: '', + optionOpening: '', + wrapperOpening: '
', + wrapperClosure: '
', + label: { + opening: '' + } + } it('produces html from an select element with name', async () => { - const inputWidget: Select = subject(defaultProps) + const inputWidget: Select = new Select(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() expect(result).toEqual(expect.stringContaining('')) }) + it('produces the options for the select element', async () => { + const inputWidget: Select = new Select(uiElement.props, uiElement.name, widgetConfig) + const result = inputWidget.renderToString() + expect(result).toEqual(expect.stringContaining('')) + expect(result).toEqual(expect.stringContaining('')) + }) + it('produces a label for the select element', async () => { - const inputWidget: Select = subject(defaultProps) + const inputWidget: Select = new Select(uiElement.props, uiElement.name, widgetConfig) const result = inputWidget.renderToString() expect(result).toEqual(expect.stringContaining('')) }) - it('produces the options for the select element', async () => { - const inputWidget: Select = subject(defaultProps) - const result = inputWidget.renderToString() - expect(result).toEqual(expect.stringContaining('')) - expect(result).toEqual(expect.stringContaining('')) + it('produces a wrapper for the input element', () => { + const inputWidget: Select = new Select(uiElement.props, uiElement.name, widgetConfig) + const result = inputWidget.renderToString() + expect(result).toEqual(expect.stringMatching(/^
(.|\s)*<\/div>$/)) }) }) }) From fe6805be611855b146cbfaa848fa31c92c6a0b15 Mon Sep 17 00:00:00 2001 From: Willian Date: Mon, 1 Jul 2019 22:13:08 -0300 Subject: [PATCH 10/12] Update dist files --- dist/interfaces/app-config.d.ts | 5 ++++ dist/utils/prop.js | 19 ++------------- dist/widgets/button.d.ts | 4 ++- dist/widgets/button.js | 16 ++++++++---- dist/widgets/checkbox.d.ts | 4 ++- dist/widgets/checkbox.js | 23 +++++++++++------ dist/widgets/input.d.ts | 1 - dist/widgets/input.js | 14 +++-------- dist/widgets/radio.d.ts | 4 ++- dist/widgets/radio.js | 39 +++++++++++++++++------------ dist/widgets/select.d.ts | 7 ++++-- dist/widgets/select.js | 42 +++++++++++++++++++++++--------- dist/widgets/widget-factory.d.ts | 4 +++ dist/widgets/widget-factory.js | 30 ++++++++++++++++++++--- dist/widgets/wrapper.d.ts | 2 ++ dist/widgets/wrapper.js | 10 ++++++++ 16 files changed, 147 insertions(+), 77 deletions(-) create mode 100644 dist/widgets/wrapper.d.ts create mode 100644 dist/widgets/wrapper.js diff --git a/dist/interfaces/app-config.d.ts b/dist/interfaces/app-config.d.ts index 533c6d2..9f58ef3 100644 --- a/dist/interfaces/app-config.d.ts +++ b/dist/interfaces/app-config.d.ts @@ -1,12 +1,17 @@ export interface AppConfig { widgets?: { input?: WidgetConfig; + radio?: WidgetConfig; + checkbox?: WidgetConfig; + select?: WidgetConfig; label?: LabelConfig; }; } export interface WidgetConfig { opening: string; closure?: string; + optionOpening?: string; + optionClosure?: string; wrapperOpening?: string; wrapperClosure?: string; label?: LabelConfig; diff --git a/dist/utils/prop.js b/dist/utils/prop.js index 131cca6..b4aede4 100644 --- a/dist/utils/prop.js +++ b/dist/utils/prop.js @@ -1,5 +1,6 @@ 'use strict' Object.defineProperty(exports, '__esModule', { value: true }) +const case_1 = require('case') exports.PROPS_INJECTION_POINT = '%s' function formatProperties(props, validProperties) { const translateProp = key => { @@ -11,23 +12,7 @@ function formatProperties(props, validProperties) { } } const getFormattedProp = key => { - let value = props[key] - const invalidIdPattern = /^\/\// - if (key === 'id') { - let newKey = key - // TODO: replace test wit str.match(pattern) - if (!invalidIdPattern.test(value)) { - const validIdPattern = /^#|~/ - const validClassPattern = /^\./ - if (validIdPattern.test(value)) { - value = value.toString().replace(validIdPattern, '') - } else if (validClassPattern.test(value)) { - newKey = 'class' - value = value.toString().replace(validClassPattern, '') - } - return `${translateProp(newKey)}="${value}"` - } - } + let value = case_1.camel(props[key].toString()) return `${translateProp(key)}="${value}"` } const formatValid = (result, prop) => { diff --git a/dist/widgets/button.d.ts b/dist/widgets/button.d.ts index 906d5f2..22f036a 100644 --- a/dist/widgets/button.d.ts +++ b/dist/widgets/button.d.ts @@ -1,7 +1,9 @@ import { Widget } from 'concordialang-ui-core'; +import { WidgetConfig } from '../interfaces/app-config'; export default class Button extends Widget { + private _config; private readonly VALID_PROPERTIES; - constructor(props: any, name?: string); + constructor(props: any, name: string, _config: WidgetConfig); renderToString(): string; private getType; } diff --git a/dist/widgets/button.js b/dist/widgets/button.js index 3c35e32..d77d82d 100644 --- a/dist/widgets/button.js +++ b/dist/widgets/button.js @@ -3,18 +3,24 @@ Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') const prop_1 = require('../utils/prop') class Button extends concordialang_ui_core_1.Widget { - constructor(props, name) { + constructor(props, name, _config) { super(props, name || '') + this._config = _config this.VALID_PROPERTIES = ['id', 'disabled', 'value'] } renderToString() { - // const inputType = this.getType(this.props.datatype as string) - const properties = prop_1.formatProperties( + const buttonType = this.getType(this.props.datatype) + let properties = prop_1.formatProperties( this.props, this.VALID_PROPERTIES ) - // return `` - return `` + properties = `${buttonType} ${properties}` + const buttonOpening = this._config.opening.replace( + prop_1.PROPS_INJECTION_POINT, + properties + ) + const buttonClosure = this._config.closure + return buttonOpening + this.name + buttonClosure } getType(datatype) { return `type="${datatype || 'button'}"` diff --git a/dist/widgets/checkbox.d.ts b/dist/widgets/checkbox.d.ts index b7204c6..8128427 100644 --- a/dist/widgets/checkbox.d.ts +++ b/dist/widgets/checkbox.d.ts @@ -1,6 +1,8 @@ import { Widget } from 'concordialang-ui-core'; +import { WidgetConfig } from '../interfaces/app-config'; export default class Checkbox extends Widget { + private _config; private readonly VALID_PROPERTIES; - constructor(props: any, name: string); + constructor(props: any, name: string, _config: WidgetConfig); renderToString(): string; } diff --git a/dist/widgets/checkbox.js b/dist/widgets/checkbox.js index f322947..4762708 100644 --- a/dist/widgets/checkbox.js +++ b/dist/widgets/checkbox.js @@ -2,22 +2,29 @@ Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') const prop_1 = require('../utils/prop') +const wrapper_1 = require('./wrapper') class Checkbox extends concordialang_ui_core_1.Widget { - constructor(props, name) { + constructor(props, name, _config) { super(props, name) + this._config = _config this.VALID_PROPERTIES = ['value', 'required'] } - // TODO: remove \n renderToString() { - const properties = prop_1.formatProperties( + const inputType = 'type="checkbox"' + let properties = prop_1.formatProperties( this.props, this.VALID_PROPERTIES ) - if (properties) - return `
\n${ - this.name - }\n
` - return `
\n${this.name}\n
` + properties = `${inputType} ${properties}` + const inputOpening = this._config.opening.replace( + prop_1.PROPS_INJECTION_POINT, + properties + ) + const inputClosure = this._config.closure || '' + return wrapper_1.wrap( + inputOpening + this.name + inputClosure, + this._config + ) } } exports.default = Checkbox diff --git a/dist/widgets/input.d.ts b/dist/widgets/input.d.ts index eb72d3a..e95736b 100644 --- a/dist/widgets/input.d.ts +++ b/dist/widgets/input.d.ts @@ -5,6 +5,5 @@ export default class Input extends Widget { private readonly VALID_PROPERTIES; constructor(props: any, name: string, _config: WidgetConfig); renderToString(): string; - private wrap; private getType; } diff --git a/dist/widgets/input.js b/dist/widgets/input.js index 901800c..3a81976 100644 --- a/dist/widgets/input.js +++ b/dist/widgets/input.js @@ -3,6 +3,7 @@ Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') const prop_1 = require('../utils/prop') const label_1 = require('./label') +const wrapper_1 = require('./wrapper') class Input extends concordialang_ui_core_1.Widget { constructor(props, name, _config) { super(props, name) @@ -22,7 +23,7 @@ class Input extends concordialang_ui_core_1.Widget { this.props, this.VALID_PROPERTIES ) - const input = this._config.opening.replace( + const inputOpening = this._config.opening.replace( prop_1.PROPS_INJECTION_POINT, `${inputType} ${properties}` ) @@ -32,16 +33,7 @@ class Input extends concordialang_ui_core_1.Widget { this.props.id.toString(), this._config ) - return this.wrap(label + input + inputClosure) - } - wrap(elements) { - if (this._config.wrapperOpening && this._config.wrapperClosure) - return ( - this._config.wrapperOpening + - elements + - this._config.wrapperClosure - ) - return elements + return wrapper_1.wrap(label + inputOpening + inputClosure, this._config) } getType(datatype) { let typeProperty diff --git a/dist/widgets/radio.d.ts b/dist/widgets/radio.d.ts index 594884f..e7a0a80 100644 --- a/dist/widgets/radio.d.ts +++ b/dist/widgets/radio.d.ts @@ -1,6 +1,8 @@ import { Widget } from 'concordialang-ui-core'; +import { WidgetConfig } from '../interfaces/app-config'; export default class Radio extends Widget { + private _config; private readonly VALID_PROPERTIES; - constructor(props: any, name: string); + constructor(props: any, name: string, _config: WidgetConfig); renderToString(): string; } diff --git a/dist/widgets/radio.js b/dist/widgets/radio.js index c1c3c1d..c3b4012 100644 --- a/dist/widgets/radio.js +++ b/dist/widgets/radio.js @@ -3,28 +3,37 @@ Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') const prop_1 = require('../utils/prop') const label_1 = require('./label') +const wrapper_1 = require('./wrapper') class Radio extends concordialang_ui_core_1.Widget { - constructor(props, name) { + constructor(props, name, _config) { super(props, name) + this._config = _config this.VALID_PROPERTIES = ['value'] } - // TODO: remove \n renderToString() { - const properties = prop_1.formatProperties( - this.props, - this.VALID_PROPERTIES - ) + const inputType = 'type="radio"' + const label = label_1.createLabel(this.name, '', this._config) let inputs = [] - const label = label_1.createLabel(this.name, this.props.id.toString()) - const inputName = this.name.toLowerCase() - if (properties) { - for (let value of this.props.value) { - let input = `${value}` - inputs.push(input) - } - return `
\n${label + inputs.join('\n')}\n
` + for (let value of this.props.value) { + // TODO: o que fazer no formatProperties em relação ao value? + // provavelmente terei que instalar o pacote "case" + // para ter 'value="algumaCoisa"', quando value for "Alguma Coisa" + // + // TODO: adicionar propriedades 'id' e 'nome' + const props = Object.assign({}, this.props, { value }) + let properties = prop_1.formatProperties( + props, + this.VALID_PROPERTIES + ) + properties = `${inputType} ${properties}` + const inputOpening = this._config.opening.replace( + prop_1.PROPS_INJECTION_POINT, + properties + ) + const inputClosure = this._config.closure || '' + inputs.push(inputOpening + value + inputClosure) } - return '
\n\n
' + return wrapper_1.wrap(label + inputs.join(''), this._config) } } exports.default = Radio diff --git a/dist/widgets/select.d.ts b/dist/widgets/select.d.ts index 463e827..1a81fc7 100644 --- a/dist/widgets/select.d.ts +++ b/dist/widgets/select.d.ts @@ -1,7 +1,10 @@ import { Widget } from 'concordialang-ui-core'; +import { WidgetConfig } from '../interfaces/app-config'; export default class Select extends Widget { - private readonly VALID_PROPERTIES; - constructor(props: any, name: string); + private _config; + private readonly SELECT_VALID_PROPERTIES; + private readonly OPTION_VALID_PROPERTIES; + constructor(props: any, name: string, _config: WidgetConfig); renderToString(): string; private getOptions; } diff --git a/dist/widgets/select.js b/dist/widgets/select.js index fc0979c..f748755 100644 --- a/dist/widgets/select.js +++ b/dist/widgets/select.js @@ -3,30 +3,50 @@ Object.defineProperty(exports, '__esModule', { value: true }) const concordialang_ui_core_1 = require('concordialang-ui-core') const prop_1 = require('../utils/prop') const label_1 = require('./label') +const wrapper_1 = require('./wrapper') class Select extends concordialang_ui_core_1.Widget { - constructor(props, name) { + constructor(props, name, _config) { super(props, name) - this.VALID_PROPERTIES = ['id', 'required'] + this._config = _config + this.SELECT_VALID_PROPERTIES = ['id', 'required'] + this.OPTION_VALID_PROPERTIES = ['value'] } - // TODO: remove \n renderToString() { const properties = prop_1.formatProperties( this.props, - this.VALID_PROPERTIES + this.SELECT_VALID_PROPERTIES ) - if (!properties) return '
\n\n
' + const selectOpening = this._config.opening.replace( + prop_1.PROPS_INJECTION_POINT, + properties + ) + const selectClosure = this._config.closure const options = this.getOptions() - const select = `\n` - const label = label_1.createLabel(this.name, this.props.id.toString()) - return `
\n${label + select}
` + const select = selectOpening + options + selectClosure + const label = label_1.createLabel( + this.name, + this.props.id.toString(), + this._config + ) + return wrapper_1.wrap(label + select, this._config) } getOptions() { + if (!this._config.optionOpening) return '' let options = [] for (let value of this.props.value) { - let option = `` - options.push(option) + const optionProps = { value } + const properties = prop_1.formatProperties( + optionProps, + this.OPTION_VALID_PROPERTIES + ) + const optionOpening = this._config.optionOpening.replace( + prop_1.PROPS_INJECTION_POINT, + properties + ) + const optionClosure = this._config.optionClosure + options.push(optionOpening + value + optionClosure) } - return options.join('\n') + return options.join('') } } exports.default = Select diff --git a/dist/widgets/widget-factory.d.ts b/dist/widgets/widget-factory.d.ts index 5cd426e..417a0cf 100644 --- a/dist/widgets/widget-factory.d.ts +++ b/dist/widgets/widget-factory.d.ts @@ -5,4 +5,8 @@ export default class WidgetFactory { constructor(_config: AppConfig); create(element: UiElement): Widget; private createInputElement; + private createRadioElement; + private createCheckboxElement; + private createSelectElement; + private createButtonElement; } diff --git a/dist/widgets/widget-factory.js b/dist/widgets/widget-factory.js index f5a1d63..c5dfd23 100644 --- a/dist/widgets/widget-factory.js +++ b/dist/widgets/widget-factory.js @@ -15,13 +15,13 @@ class WidgetFactory { case 'textbox' /* TEXTBOX */: return this.createInputElement(element) case 'button' /* BUTTON */: - return new button_1.default(element.props, element.name) + return this.createButtonElement(element) case 'checkbox' /* CHECKBOX */: - return new checkbox_1.default(element.props, element.name) + return this.createCheckboxElement(element) case 'radio' /* RADIO */: - return new radio_1.default(element.props, element.name) + return this.createRadioElement(element) case 'select' /* SELECT */: - return new select_1.default(element.props, element.name) + return this.createSelectElement(element) default: throw new Error(`Invalid widget type: ${element.widget}`) } @@ -32,5 +32,27 @@ class WidgetFactory { widgetConfig.label || lodash_1.get(this._config, 'widgets.label') return new input_1.default(element.props, element.name, widgetConfig) } + createRadioElement(element) { + const widgetConfig = lodash_1.get(this._config, 'widgets.radio') + widgetConfig.label = + widgetConfig.label || lodash_1.get(this._config, 'widgets.label') + return new radio_1.default(element.props, element.name, widgetConfig) + } + createCheckboxElement(element) { + const widgetConfig = lodash_1.get(this._config, 'widgets.checkbox') + widgetConfig.label = + widgetConfig.label || lodash_1.get(this._config, 'widgets.label') + return new checkbox_1.default(element.props, element.name, widgetConfig) + } + createSelectElement(element) { + const widgetConfig = lodash_1.get(this._config, 'widgets.select') + widgetConfig.label = + widgetConfig.label || lodash_1.get(this._config, 'widgets.label') + return new select_1.default(element.props, element.name, widgetConfig) + } + createButtonElement(element) { + const widgetConfig = lodash_1.get(this._config, 'widgets.button') + return new button_1.default(element.props, element.name, widgetConfig) + } } exports.default = WidgetFactory diff --git a/dist/widgets/wrapper.d.ts b/dist/widgets/wrapper.d.ts new file mode 100644 index 0000000..63e9a5b --- /dev/null +++ b/dist/widgets/wrapper.d.ts @@ -0,0 +1,2 @@ +import { WidgetConfig } from '../interfaces/app-config'; +export declare function wrap(elements: string, widgetConfig: WidgetConfig): string; diff --git a/dist/widgets/wrapper.js b/dist/widgets/wrapper.js new file mode 100644 index 0000000..45fa851 --- /dev/null +++ b/dist/widgets/wrapper.js @@ -0,0 +1,10 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +function wrap(elements, widgetConfig) { + if (widgetConfig.wrapperOpening && widgetConfig.wrapperClosure) + return ( + widgetConfig.wrapperOpening + elements + widgetConfig.wrapperClosure + ) + return elements +} +exports.wrap = wrap From 055ef2275137970e5ece00c2f964d54d1fbdd701 Mon Sep 17 00:00:00 2001 From: Willian Date: Tue, 2 Jul 2019 01:23:54 -0300 Subject: [PATCH 11/12] Fix tests --- src/commands/generate.ts | 2 +- src/html-ui-prototyper.ts | 5 +++- test/commands/generate.spec.ts | 24 +++++++++++++++-- ...tor.spec.ts => html-ui-prototyper.spec.ts} | 26 ++++++++++++++++--- 4 files changed, 49 insertions(+), 8 deletions(-) rename test/{generator.spec.ts => html-ui-prototyper.spec.ts} (67%) diff --git a/src/commands/generate.ts b/src/commands/generate.ts index 1f59803..51468d9 100644 --- a/src/commands/generate.ts +++ b/src/commands/generate.ts @@ -21,7 +21,7 @@ export default class Generate extends Command { const processResult: ProcessResult = JSON.parse(flags.features) as ProcessResult const generator = new HtmlUIPrototyper(fs, flags.outputDir) const result = await generator.generate(processResult.features) - this.log(JSON.stringify(result)) + this.log(result.join('\n')) } } } diff --git a/src/html-ui-prototyper.ts b/src/html-ui-prototyper.ts index b4a091a..77f443a 100644 --- a/src/html-ui-prototyper.ts +++ b/src/html-ui-prototyper.ts @@ -15,6 +15,9 @@ export default class HtmlUIPrototyper implements Prototyper { public async generate(features: Feature[]): Promise { const appConfig: AppConfig = this.getAppConfig() const factory = new WidgetFactory(appConfig) + + if (features.length === 0) return Promise.resolve([ 'No features found' ]) + const createFilePromises: Promise[] = [] for (let feature of features) { @@ -30,7 +33,7 @@ export default class HtmlUIPrototyper implements Prototyper { return result + widget.renderToString() }, '') - content = prettier.format(`
\n${content}
`, {parser: 'html', htmlWhitespaceSensitivity: 'ignore'}) + content = prettier.format(`
${content}
`, {parser: 'html', htmlWhitespaceSensitivity: 'ignore'}) const path = format({ dir: this._outputDir, name: fileName, ext: '.html' }) await promisify(fs.writeFile)(path, content) diff --git a/test/commands/generate.spec.ts b/test/commands/generate.spec.ts index f6e04f0..748335d 100644 --- a/test/commands/generate.spec.ts +++ b/test/commands/generate.spec.ts @@ -1,11 +1,31 @@ +import { fs, vol } from 'memfs' +const cosmiconfig = require('cosmiconfig') + import Generate from '../../src/commands/generate' +jest.mock('cosmiconfig') + describe('Generate', () => { + const CURRENT_DIR: string = process.cwd() + + beforeEach(() => { + vol.fromJSON({ + './concordialang-ui-html.json': '{}' + }, CURRENT_DIR) + + const explorer = { + loadSync: () => ({ + config: vol.readFileSync(`${ CURRENT_DIR }/concordialang-ui-html.json`, 'utf8') + }) + } + cosmiconfig.mockReturnValue(explorer) + }) + it('should print a JSON content', async () => { let spy = jest.spyOn(process.stdout, 'write'); - await Generate.run(['--features', '[]', '--outputDir', 'outputDir']) - expect(spy).not.toBeCalled() + await Generate.run(['--features', '{ "features": [] }', '--outputDir', 'outputDir']) + expect(spy).toBeCalledWith("No features found\n") }) }) diff --git a/test/generator.spec.ts b/test/html-ui-prototyper.spec.ts similarity index 67% rename from test/generator.spec.ts rename to test/html-ui-prototyper.spec.ts index b917c69..698ae9a 100644 --- a/test/generator.spec.ts +++ b/test/html-ui-prototyper.spec.ts @@ -2,19 +2,35 @@ import { Feature } from 'concordialang-ui-core' import { minify } from 'html-minifier' import { fs, vol } from 'memfs' import { promisify } from 'util' +const cosmiconfig = require('cosmiconfig') import HtmlUIPrototyper from '../src/html-ui-prototyper' +jest.mock('cosmiconfig') + describe('HtmlUIPrototyper', () => { const CURRENT_DIR: string = process.cwd() - let prototyper: HtmlUIPrototyper | null + const appConfig = { + widgets: { + input: {}, + label: {} + } + } beforeEach(() => { vol.fromJSON({ - '/concordialang-ui-html.json': '{}' + './concordialang-ui-html.json': JSON.stringify(appConfig) }, CURRENT_DIR) + + const explorer = { + loadSync: () => ({ + config: vol.readFileSync(`${ CURRENT_DIR }/concordialang-ui-html.json`, 'utf8') + }) + } + cosmiconfig.mockReturnValue(explorer) + prototyper = new HtmlUIPrototyper(fs, CURRENT_DIR) // In-memory fs }) @@ -43,8 +59,10 @@ describe('HtmlUIPrototyper', () => { expect(produced).toEqual(expected) } - it('produces an HTML file from features', async () => { - const features: Feature[] = [ /* something here */ ] + // FIXME the content of app config file is a string. It should be an object. + // Maybe we will have to mock loadJson from cosmiconfig. + xit('produces an HTML file from features', async () => { + const features: Feature[] = [ { name: 'Test Feature', uiElements: [ { name: 'Name', widget: 'textbox', props: { id: 'name' }, position: 0 } ], position: 0 } ] const htmls: string[] = [ /* put the expected html here */]; await expectFeaturesToProduceHtml(features, htmls) }) From 6c73bbe0b6674be1460aa4f1fe55cb0ec0289d12 Mon Sep 17 00:00:00 2001 From: Willian Date: Tue, 2 Jul 2019 01:24:14 -0300 Subject: [PATCH 12/12] Update dist files --- dist/commands/generate.js | 2 +- dist/html-ui-prototyper.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/dist/commands/generate.js b/dist/commands/generate.js index 93cad7e..c4a6d94 100644 --- a/dist/commands/generate.js +++ b/dist/commands/generate.js @@ -15,7 +15,7 @@ class Generate extends command_1.Command { flags.outputDir ) const result = yield generator.generate(processResult.features) - this.log(JSON.stringify(result)) + this.log(result.join('\n')) } }) } diff --git a/dist/html-ui-prototyper.js b/dist/html-ui-prototyper.js index 1b3ad06..1a378e9 100644 --- a/dist/html-ui-prototyper.js +++ b/dist/html-ui-prototyper.js @@ -16,6 +16,8 @@ class HtmlUIPrototyper { return tslib_1.__awaiter(this, void 0, void 0, function*() { const appConfig = this.getAppConfig() const factory = new widget_factory_1.default(appConfig) + if (features.length === 0) + return Promise.resolve(['No features found']) const createFilePromises = [] for (let feature of features) { const elements = feature.uiElements.map(uiElement => @@ -33,7 +35,7 @@ class HtmlUIPrototyper { let content = widgets.reduce((result, widget) => { return result + widget.renderToString() }, '') - content = prettier.format(`
\n${content}
`, { + content = prettier.format(`
${content}
`, { parser: 'html', htmlWhitespaceSensitivity: 'ignore', })